From 48dac0217a2d939a000d59708d7b9120a712dba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Mon, 19 Oct 2026 17:46:36 -0300 Subject: [PATCH 1/2] feat(uftp): build uftp for the openEuler targets The openEuler targets did not build uftp, and openEuler does not ship UFTP, so xCAT could not distribute openEuler stateless images over UFTP. The native openEuler profile of mockbuild-all.pl now runs the uftp builder, and every openEuler section of packages-manifest.conf lists uftp=5.0.4. The ppc64le target resolves its manifest through the native input catalog, so the catalog declares uftp as an owner that builds as UID 1000, like ipmitool-xcat, and the catalog loader accepts that owner. The spec needs gcc, make and openssl-devel, which the OS repository of every openEuler release has. That is the only repository of the ppc64le target. The 20.03 and 22.03 builds link OpenSSL 1.1.1. --- BUILD.md | 8 ++++---- lib/XCAT/NativeInputs.pm | 2 +- mockbuild-all.pl | 2 +- openeuler/24.03-ppc64le.inputs.json | 13 +++++++++++++ packages-manifest.conf | 12 +++++++++--- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/BUILD.md b/BUILD.md index 17943b7..31e5b1b 100644 --- a/BUILD.md +++ b/BUILD.md @@ -66,7 +66,7 @@ listed for it; a package absent from a target's section is not built for that ta perl set differs because the OS/EPEL already provides some modules). Note `conserver-xcat` is **not** pulled in by `dnf install xCAT` (goconserver superseded it), yet it is listed in — and therefore built for — every target, because some deployments still use it. `uftp` is not pulled in either, -and every EL target lists it (see "Packages notes"). The lists were derived empirically — on a clean MN of each +and every EL and openEuler target lists it (see "Packages notes"). The lists were derived empirically — on a clean MN of each (EL, arch), `dnf install xCAT` from xcat.org latest, and the packages whose `from_repo=xcat-dep` are exactly the required set. See the file header for details. @@ -99,9 +99,9 @@ matching MN and installs xCAT + the freshly built xcat-dep there). `conserver-xcat` explicitly (it is **not** pulled in as a dependency), disable the `goconserver` service and enable the `conserver` service. - **`uftp`** is UFTP 5.0.4, the multicast file transfer tool, built from the upstream source with - the fixes in `uftp/00*.patch`. It is built as an rpm for every EL - target and as a deb for every Ubuntu target. RHEL and EPEL do not ship it, and Ubuntu ships UFTP - 4.10, which does not work with UFTP 5. xCAT does not require it: install `uftp` on the management + the fixes in `uftp/00*.patch`. It is built as an rpm for every EL and openEuler target and as a + deb for every Ubuntu target. RHEL, EPEL and openEuler do not ship it, and Ubuntu ships UFTP 4.10, + which does not work with UFTP 5. xCAT does not require it: install `uftp` on the management node (the `uftp` sender) and in a diskless image (the `uftpd` receiver) to distribute images over UFTP. The package enables no service. The deb replaces the Ubuntu `uftp` package, and removes the init script and the logrotate file of that package, which started `uftpd` as a service. diff --git a/lib/XCAT/NativeInputs.pm b/lib/XCAT/NativeInputs.pm index 02fef86..eb83247 100644 --- a/lib/XCAT/NativeInputs.pm +++ b/lib/XCAT/NativeInputs.pm @@ -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 ipxe-xcat syslinux-xcat xnba-undi xCAT-genesis-base + qw(goconserver grub2-xcat ipmitool-xcat ipxe-xcat syslinux-xcat uftp xnba-undi xCAT-genesis-base perl-Crypt-Rijndael perl-Crypt-SSLeay perl-HTTP-Async perl-IO-Stty perl-Net-DNS perl-Net-HTTPS-NB perl-Net-Telnet); } if ($type ne 'publisher') { diff --git a/mockbuild-all.pl b/mockbuild-all.pl index c2fafff..46a50c7 100755 --- a/mockbuild-all.pl +++ b/mockbuild-all.pl @@ -1168,7 +1168,7 @@ sub target_profile { noarch_cfg => $target, forcearch => 0, epel => 0, - dep_builders => [qw(grub2-xcat ipmitool-xcat syslinux-xcat goconserver conserver-xcat xnba-undi ipxe-xcat python3-scp)], + dep_builders => [qw(grub2-xcat ipmitool-xcat syslinux-xcat goconserver conserver-xcat xnba-undi ipxe-xcat uftp python3-scp)], required => [qw(ipmitool-xcat syslinux-xcat grub2-xcat xnba-undi ipxe-xcat perl-IO-Stty perl-HTTP-Async perl-Net-HTTPS-NB)], }; diff --git a/openeuler/24.03-ppc64le.inputs.json b/openeuler/24.03-ppc64le.inputs.json index cf3124b..dd6e499 100644 --- a/openeuler/24.03-ppc64le.inputs.json +++ b/openeuler/24.03-ppc64le.inputs.json @@ -1108,6 +1108,19 @@ ], "build_uid": 1000 }, + { + "name": "uftp", + "type": "owner", + "outputs": [ + "uftp", + "uftp-debuginfo", + "uftp-debugsource" + ], + "needs": [ + "procenv" + ], + "build_uid": 1000 + }, { "name": "xCAT-genesis-base", "type": "owner", diff --git a/packages-manifest.conf b/packages-manifest.conf index cf69ce4..a8a5600 100644 --- a/packages-manifest.conf +++ b/packages-manifest.conf @@ -51,9 +51,9 @@ # conserver-xcat is NOT pulled by `dnf install xCAT` (goconserver superseded it), # but it is built for every target anyway because some users still deploy it. # -# uftp is NOT pulled by `dnf install xCAT` either. It is built for every EL target so that a -# management node can install the uftp sender, and a diskless image the uftpd receiver, when the -# cluster distributes images over UFTP multicast. RHEL and EPEL do not ship UFTP. +# uftp is NOT pulled by `dnf install xCAT` either. It is built for every EL and openEuler target so +# that a management node can install the uftp sender, and a diskless image the uftpd receiver, when +# the cluster distributes images over UFTP multicast. RHEL, EPEL and openEuler do not ship UFTP. [alma+epel-8-x86_64] conserver-xcat=8.2.1 @@ -269,6 +269,7 @@ grub2-xcat=1.0 ipmitool-xcat=>= 1.8.18-4 ipxe-xcat=2.0.0 syslinux-xcat=>= 6.03-1 +uftp=5.0.4 xnba-undi=>= 1.21.1-1 perl-Crypt-Rijndael=1.13 perl-Crypt-SSLeay=0.72 @@ -286,6 +287,7 @@ grub2-xcat=1.0 ipmitool-xcat=>= 1.8.18-4 ipxe-xcat=2.0.0 syslinux-xcat=>= 6.03-1 +uftp=5.0.4 xnba-undi=>= 1.21.1-1 perl-Crypt-Rijndael=1.13 perl-Crypt-SSLeay=0.72 @@ -300,6 +302,7 @@ goconserver=>= 0.3.3-snap202011021058 grub2-xcat=1.0 ipmitool-xcat=>= 1.8.18-4 syslinux-xcat=>= 6.03-1 +uftp=5.0.4 xnba-undi=>= 1.21.1-1 perl-Crypt-Rijndael=1.13 perl-Crypt-SSLeay=0.72 @@ -314,6 +317,7 @@ goconserver=>= 0.3.3-snap202011021058 grub2-xcat=1.0 ipmitool-xcat=>= 1.8.18-4 syslinux-xcat=>= 6.03-1 +uftp=5.0.4 xnba-undi=>= 1.21.1-1 perl-Crypt-Rijndael=1.13 perl-Crypt-SSLeay=0.72 @@ -329,6 +333,7 @@ grub2-xcat=1.0 ipmitool-xcat=>= 1.8.18-4 ipxe-xcat=2.0.0 syslinux-xcat=>= 6.03-1 +uftp=5.0.4 xnba-undi=>= 1.21.1-1 perl-Crypt-Rijndael=1.13 perl-Crypt-SSLeay=0.72 @@ -344,6 +349,7 @@ grub2-xcat=1.0 ipmitool-xcat=>= 1.8.18-4 ipxe-xcat=2.0.0 syslinux-xcat=>= 6.03-1 +uftp=5.0.4 xnba-undi=>= 1.21.1-1 perl-Crypt-Rijndael=1.13 perl-Crypt-SSLeay=0.72 From 4e5c72bbb5e039b10d5b1f146e30f2cb598764cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Mon, 19 Oct 2026 17:46:40 -0300 Subject: [PATCH 2/2] test(uftp): require uftp in every openEuler target Every openEuler section of packages-manifest.conf must list uftp. The ppc64le section is no longer exempt from the package parity check with the EL10 ppc64le section, so its native input catalog must declare an owner for uftp. native/uftp-openeuler.t runs mockbuild-all.pl --dry-run and checks that an openEuler target plans the uftp builder in its own mock config, and only when its manifest section lists uftp. CI runs it with the other native tests. --- .github/workflows/genesis-openembedded.yml | 4 +- native/uftp-openeuler.t | 81 ++++++++++++++++++++++ t/mockbuild-all.t | 8 ++- t/openeuler.t | 1 - 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 native/uftp-openeuler.t diff --git a/.github/workflows/genesis-openembedded.yml b/.github/workflows/genesis-openembedded.yml index c86062d..d29a9b5 100644 --- a/.github/workflows/genesis-openembedded.yml +++ b/.github/workflows/genesis-openembedded.yml @@ -65,6 +65,7 @@ jobs: lib/XCAT/GenesisRelease.pm \ mockbuild-all.pl \ native/uftp-fixes.t \ + native/uftp-openeuler.t \ t/build_utils.t \ t/common-repo-gate.t \ t/genesis_openembedded_release.t \ @@ -110,7 +111,8 @@ jobs: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 prove -v native/buildinfo_provenance.t native/goconserver-openeuler.t \ native/openeuler-power-inputs.t native/openeuler-srpm.t \ - native/xnba-release-suffix.t native/uftp-fixes.t 2>&1 | tee native.tap + native/xnba-release-suffix.t native/uftp-fixes.t \ + native/uftp-openeuler.t 2>&1 | tee native.tap # prove returns success when a test file skips all its checks. if grep -E '^1\.\.0 # SKIP|^native/[^ ]+\.t \.+ skipped' native.tap; then echo 'a native test file was skipped' >&2 diff --git a/native/uftp-openeuler.t b/native/uftp-openeuler.t new file mode 100644 index 0000000..d4ef7b9 --- /dev/null +++ b/native/uftp-openeuler.t @@ -0,0 +1,81 @@ +#!/usr/bin/env perl +# mockbuild-all.pl --dry-run must plan the uftp builder for an openEuler target whose manifest +# section lists uftp, with the mock config of that target, and must not plan it otherwise. +use strict; +use warnings; + +use Cwd qw(abs_path); +use File::Path qw(make_path); +use File::Temp qw(tempdir); +use FindBin qw($RealBin); +use JSON::PP qw(encode_json); +use Test::More; +use Text::ParseWords qw(shellwords); + +use lib "$RealBin/../lib", "$RealBin/../t/lib"; +use XCAT::BuildUtils qw(capture_command command_exists digest_file read_binary write_binary); +use XCAT::GenesisReleaseTest qw(run_capture); + +plan skip_all => 'Linux RPM tools and user namespaces are required' + unless $^O eq 'linux' && !grep { !command_exists($_) } qw(rpm unshare); +my $tmp = tempdir(CLEANUP => !$ENV{XCAT_TEST_KEEP}); +my @namespace = $> == 0 ? () : ('unshare', '--user', '--map-root-user'); +plan skip_all => 'User namespace is unavailable for the root check of mockbuild-all.pl' + if @namespace && run_capture("$tmp/namespace.log", @namespace, 'true') != 0; +my $collector = $ENV{XCAT_TEST_COLLECTOR} // abs_path("$RealBin/../mockbuild-all.pl"); +my $arch = capture_command('uname', '-m'); + +# Runs the dry-run on a tree whose builders die when executed, and returns the planned uftp +# builder command line, or undef when the plan has none. +sub planned_uftp { + my ($target, $with_uftp) = @_; + my $root = "$tmp/$target " . ($with_uftp ? 'with' : 'without') . ' uftp'; + make_path(map { "$root/$_" } qw(uftp goconserver openeuler)); + write_binary("$root/packages-manifest.conf", + "[$target]\ngoconserver=0.*\n" . ($with_uftp ? "uftp=5.0.4\n" : '')); + write_binary("$root/$_/mockbuild.pl", "die qq{dry-run executed a builder\\n};\n") for qw(uftp goconserver); + if ($target eq 'openeuler-24.03-ppc64le') { + my $key = 'openeuler/publisher.key'; + write_binary("$root/$key", 'dry-run key fixture'); + write_binary("$root/openeuler/24.03-ppc64le.inputs.json", encode_json({ + version => 1, target => $target, + publisher_key => {path => $key, sha256 => digest_file("$root/$key"), fingerprint => ('A' x 40)}, + inputs => [map { {name => $_, type => 'owner', outputs => [$_], build_uid => 1000} } + qw(goconserver uftp)], + })); + } + local $ENV{MOCKBUILD_ALL_MOUNTNS} = 1; + my $log = "$root.log"; + my $rc = run_capture($log, @namespace, $^X, $collector, '--repo-root', $root, + '--xcat-source', $root, '--target', $target, '--output', "$root/output", + '--build-timestamp', 1788718796, '--run-id', 'uftp-plan', '--skip-genesis', '--gpg-sign', + '--max-parallel', 1, '--parallel-builds', 1, '--dry-run'); + is($rc, 0, "$target dry-run succeeds " . ($with_uftp ? 'with' : 'without') . ' uftp') + or diag(read_binary($log)); + my ($command) = read_binary($log) =~ /^\+ ([^\n]*\Q$root\/uftp\/mockbuild.pl\E[^\n]*)$/m; + return unless defined $command; + # A native owner wraps the builder in its own shell commands. + my @argv = shellwords($command); + for (1 .. 3) { + last if $argv[0] eq 'perl'; + @argv = shellwords($argv[-1]); + } + return \@argv; +} + +my @targets = ("alma+epel-9-$arch"); +push @targets, 'openeuler-24.03sp3-x86_64', 'openeuler-20.03sp4-x86_64' if $arch eq 'x86_64'; +push @targets, 'openeuler-24.03-ppc64le' if $arch eq 'ppc64le'; +for my $target (@targets) { + my $argv = planned_uftp($target, 1); + ok($argv, "$target plans the uftp builder"); + if ($argv) { + is($argv->[0], 'perl', "$target runs the uftp builder with perl"); + my %options; + for my $i (0 .. $#$argv - 1) { $options{$argv->[$i]} = $argv->[$i + 1]; } + is($options{'--mock-cfg'}, $target, "$target builds uftp in its own mock config"); + ok(!exists $options{'--target-arch'}, "$target builds uftp natively"); + } + ok(!planned_uftp($target, 0), "$target does not plan uftp when its manifest section lacks it"); +} +done_testing(); diff --git a/t/mockbuild-all.t b/t/mockbuild-all.t index 4609ac4..32236e8 100644 --- a/t/mockbuild-all.t +++ b/t/mockbuild-all.t @@ -536,9 +536,11 @@ is(rpm_release(tempdir(CLEANUP => 1), 'nonexistent-pkg'), undef, 'rpm_release is or diag("missing ipxe-xcat in: @no_ipxe_xcat"); is_deeply(\@missing, [], 'conserver-xcat is present in every legacy manifest target section') or diag("missing conserver-xcat in: @missing"); - # uftp is optional for xCAT like conserver-xcat, and BUILD.md documents it for every EL target. - my @no_uftp = grep { !exists $m{$_}{uftp} } @targets, 'rocky-10-riscv64-xcat'; - is_deeply(\@no_uftp, [], 'uftp is present in every EL manifest target section') + # uftp is optional for xCAT like conserver-xcat, and BUILD.md documents it for every EL and + # openEuler target. + my @no_uftp = grep { !exists $m{$_}{uftp} } + @targets, 'rocky-10-riscv64-xcat', grep { /^openeuler-/ } sort keys %m; + is_deeply(\@no_uftp, [], 'uftp is present in every EL and openEuler manifest target section') or diag("missing uftp in: @no_uftp"); my @native_missing = grep { /^openeuler-/ && !exists $m{$_}{goconserver} } sort keys %m; is_deeply(\@native_missing, [], 'native manifest targets retain goconserver'); diff --git a/t/openeuler.t b/t/openeuler.t index b575f8c..b9e7336 100644 --- a/t/openeuler.t +++ b/t/openeuler.t @@ -64,7 +64,6 @@ for my $path ( my %exempt = ( 'conserver-xcat' => 'xCAT requires goconserver; no core rpm requires conserver-xcat', 'elilo-xcat' => 'no core rpm requires elilo-xcat', - 'uftp' => 'no core rpm requires uftp', ); my $reference = 'alma+epel-10-ppc64le'; ok(scalar keys %{$manifest{$reference}}, "$reference is the reference section and is not empty");