mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-10-21 07:08:12 +00:00
fix(xcat-core): the mock result directory owner ignores include() and stale logs
mock_build_owner parsed chrootuid and chrootgid from the text of the rendered configuration. A value set in an included file, an assignment with an inline comment or a double-quoted key, and an include after an assignment all gave a uid that mock does not build as. Also, a root build that stopped part way left root-owned 0644 logs in the result directories, and the next build, as uid 1000, could not append to them. mock_build_owner now asks mock's own loader, mockbuild.config.load_config, for chrootuid and chrootgid of the chroot that buildrpms.pl passes to mock -r. It fails with a clear message when mock is not installed. prepare_mock_resultdirs moves to XCAT::BuildUtils. It also gives the files already in both result directories to that owner, so a retry can append to the old logs and replace a package of the same version. When mock builds as the caller, nothing changes owner. native/mock_resultdir_owner.t gave the wrong uid for four of its configuration cases, and failed the 11 retry checks, before this change. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
@@ -42,7 +42,7 @@ our @EXPORT_OK = qw(
|
||||
buildinfo_text
|
||||
targetarch_from_target
|
||||
openeuler_build_target openeuler_repo_subdir
|
||||
mock_config_text mock_build_owner
|
||||
mock_config_text mock_build_owner prepare_mock_resultdirs
|
||||
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
|
||||
@@ -1160,32 +1160,77 @@ sub mock_config_text {
|
||||
|
||||
=head3 mock_build_owner
|
||||
|
||||
Descriptions: Report the uid and gid mock creates its --resultdir as.
|
||||
|
||||
mock creates the result directory and its logs as chrootuid, and buildrpms.pl
|
||||
passes a relative one under a tree it owns as root. The caller gives the
|
||||
directory to this owner before the build starts.
|
||||
|
||||
No mock template declares chrootuid or chrootgid (56 on the ppc64le builder,
|
||||
none), so the target configuration carries the whole answer.
|
||||
Descriptions: Report the uid and gid mock builds as, from mock's own
|
||||
configuration loader. The loader resolves include() and
|
||||
the assignments around it as a build does.
|
||||
|
||||
Arguments:
|
||||
$text - the rendered mock configuration
|
||||
$chroot - the name passed to mock -r
|
||||
$configdir - the mock configuration directory; mock's default when undef
|
||||
|
||||
Returns: ($uid, $gid), each undef when the configuration declares none. mock
|
||||
then builds as the calling user, and the directory needs no change.
|
||||
Returns: ($uid, $gid). With no chrootuid, $uid is the caller, as in mock.
|
||||
$gid is undef when the loader reports none.
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
my $MOCK_OWNER_LOADER = <<'PYTHON';
|
||||
import sys
|
||||
try:
|
||||
from mockbuild.config import MOCKCONFDIR, load_config
|
||||
except ImportError:
|
||||
sys.exit('mock is not installed: cannot import mockbuild.config')
|
||||
opts = load_config(sys.argv[2] or MOCKCONFDIR, sys.argv[1])
|
||||
print(opts['chrootuid'], opts.get('chrootgid', ''))
|
||||
PYTHON
|
||||
|
||||
sub mock_build_owner {
|
||||
my ($text) = @_;
|
||||
my ($uid, $gid);
|
||||
# mock takes the last assignment.
|
||||
for my $line (split /\n/, $text) {
|
||||
$uid = $1 if $line =~ /\Aconfig_opts\['chrootuid'\]\s*=\s*(\d+)\s*\z/;
|
||||
$gid = $1 if $line =~ /\Aconfig_opts\['chrootgid'\]\s*=\s*(\d+)\s*\z/;
|
||||
}
|
||||
return ($uid, $gid);
|
||||
my ($chroot, $configdir) = @_;
|
||||
open my $pipe, '-|', 'python3', '-c', $MOCK_OWNER_LOADER, $chroot, $configdir // ''
|
||||
or die "Cannot run python3 to load the mock configuration $chroot: $!\n";
|
||||
my $out = do { local $/; <$pipe> } // '';
|
||||
close $pipe or die "mock cannot load the configuration $chroot\n";
|
||||
my ($uid, $gid) = $out =~ /\A(\d+) (\d*)\n\z/
|
||||
or die "mock gives no chrootuid for $chroot\n";
|
||||
return ($uid, length $gid ? $gid : undef);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
=head3 prepare_mock_resultdirs
|
||||
|
||||
Descriptions: Give the --resultdir directories, and the files a previous
|
||||
build left in them, to the uid and gid mock builds as.
|
||||
mock writes its logs and packages there as chrootuid. A
|
||||
root build that stopped part way leaves root-owned 0644
|
||||
files that a non-root build cannot append to or replace.
|
||||
|
||||
Arguments:
|
||||
$chroot - the name passed to mock -r
|
||||
$configdir - the mock configuration directory; mock's default when undef
|
||||
@dirs - the result directories, created when missing
|
||||
|
||||
Returns: nothing. Dies when a chown fails.
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
sub prepare_mock_resultdirs {
|
||||
my ($chroot, $configdir, @dirs) = @_;
|
||||
my ($uid, $gid) = mock_build_owner($chroot, $configdir);
|
||||
make_path(@dirs);
|
||||
return if $uid == $>;
|
||||
$gid //= -1;
|
||||
for my $dir (@dirs) {
|
||||
opendir(my $dh, $dir) or die "Cannot read $dir: $!\n";
|
||||
my @files = grep { -f $_ && !-l $_ } map { "$dir/$_" } readdir $dh;
|
||||
closedir $dh;
|
||||
for my $path ($dir, @files) {
|
||||
chown($uid, $gid, $path) == 1
|
||||
or die "FATAL: cannot give $path to uid $uid: $!\n";
|
||||
}
|
||||
# mock writes the packages as chrootuid:chrootgid.
|
||||
chmod 0775, $dir;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-15
@@ -60,7 +60,7 @@ use XCAT::BuildUtils qw(git_revision source_date_epoch sh sh_or_die usage buildi
|
||||
stage_genesis_base_sources
|
||||
write_script read_line targetarch_from_target
|
||||
openeuler_build_target openeuler_repo_subdir
|
||||
mock_config_text mock_build_owner);
|
||||
mock_config_text);
|
||||
use POSIX (); # EEXIST, for the directory build lock (see main())
|
||||
use Getopt::Long qw(GetOptions);
|
||||
use POSIX qw(strftime);
|
||||
@@ -330,23 +330,12 @@ sub createmockconfig {
|
||||
mock_config_text($pkg, "$target$ext", read_text("/etc/mock/$target.cfg"), $SOURCE_DATE_EPOCH));
|
||||
}
|
||||
|
||||
# mock creates --resultdir and the logs under it as chrootuid, and the two mock calls below
|
||||
# pass a relative directory under dist/, which this script owns as root. Give the directory
|
||||
# to the build uid before mock runs, so the build does not need to be root to write its own
|
||||
# results. openeuler-24.03-ppc64le is the only target that declares a uid; everywhere else
|
||||
# mock builds as the caller and there is nothing to change.
|
||||
# mock writes --resultdir as chrootuid, and this script runs as root.
|
||||
sub prepare_mock_resultdirs {
|
||||
my ($pkg, $target) = @_;
|
||||
my $ext = $opts{mock_uniqueext} ? "-$opts{mock_uniqueext}" : "";
|
||||
my ($uid, $gid) = mock_build_owner(read_text("/etc/mock/$pkg-$target$ext.cfg"));
|
||||
return unless defined $uid || defined $gid;
|
||||
for my $dir ("dist/$target/rpms", "dist/$target/rpms/SRPMS") {
|
||||
make_path($dir);
|
||||
chown(defined $uid ? $uid : -1, defined $gid ? $gid : -1, $dir) == 1
|
||||
or die "FATAL: cannot give $dir to the build uid: $!\n";
|
||||
# The group needs the write bit: mock writes the rpms as chrootuid:chrootgid.
|
||||
chmod 0775, $dir;
|
||||
}
|
||||
XCAT::BuildUtils::prepare_mock_resultdirs("$pkg-$target$ext", undef,
|
||||
"dist/$target/rpms", "dist/$target/rpms/SRPMS");
|
||||
}
|
||||
|
||||
sub buildsources_genesis_base($) {
|
||||
|
||||
Reference in New Issue
Block a user