diff --git a/.github/workflows/genesis-openembedded.yml b/.github/workflows/genesis-openembedded.yml index 9a008c5..d419823 100644 --- a/.github/workflows/genesis-openembedded.yml +++ b/.github/workflows/genesis-openembedded.yml @@ -79,6 +79,7 @@ jobs: 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 diff --git a/lib/XCAT/NativeInputs.pm b/lib/XCAT/NativeInputs.pm index 065c136..2dacb62 100644 --- a/lib/XCAT/NativeInputs.pm +++ b/lib/XCAT/NativeInputs.pm @@ -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) = @_; @@ -300,4 +300,40 @@ 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"; + $out .= "config_opts['plugin_conf']['procenv_enable'] = " . ($bootstrap ? 'False' : 'True') . "\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; diff --git a/mockbuild-all.pl b/mockbuild-all.pl index 28914a3..8ae2150 100755 --- a/mockbuild-all.pl +++ b/mockbuild-all.pl @@ -1289,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"; diff --git a/t/openeuler_native_procenv_plugin.t b/t/openeuler_native_procenv_plugin.t new file mode 100644 index 0000000..256906e --- /dev/null +++ b/t/openeuler_native_procenv_plugin.t @@ -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();