2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-10-17 17:20:31 +00:00
Commit Graph

33 Commits

Author SHA1 Message Date
Daniel Hilst 562ee07d73 Merge master into fix/openeuler-ppc64le-net-dns
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-14 11:08:27 -03:00
Daniel Hilst e6f2e8a794 fix(xcat-dep): the mock result owner ignores sudo and fresh parents
mock_chroot_uid ran mock's loader as root. mock itself loads its
configuration as the user that sudo names, so with no chrootuid it
builds as SUDO_UID. The helper reported uid 0, and mock_result_dirs
gave the result directories to root.

As root, the loader now builds the uid manager with mock's own
setup_uid_manager() and loads the configuration through
run_in_subprocess_without_privileges(), as mock main() does.

make_traversable_path gives mode 0755 to the directories that it
creates, because make_path applies the umask. mock_result_dirs and
mockbuild-perl-packages.pl use it for the work and package directories.
Directories that already exist keep their mode.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-14 05:40:14 -03:00
Daniel Hilst 20110fc17d test(xcat-dep): nothing asserts which repository cell lock a target takes
The reported failure is a lock, not an architecture: xcat-dep-build-el10-aarch64
took /repos/yum/xcat-dep/rh10/.x86_64.lock on xcat-master and held it, and
xcat-dep-build-el10-x86_64 of the same run waited out 100 retries and exited
before it built anything. Builds 92 and 93 failed that way, and build 94 passed
only because it won the race. No test covers the path that is locked.

target_cell() built the cell inline from target_profile(), and cell_lock_path()
lived in mockbuild-all.pl, so neither could be called from a test. The cell and
the lock are now epel_cell_path() and cell_lock_path() in MockBuildUtils, and
target_cell() calls them. The behaviour does not change.

t/aarch64_cross_build.t resolves both EL10 targets on an x86_64 host and asserts
that their cells and their locks differ. With the architecture taken from the
host again, three of its assertions fail, among them "the two EL10 targets of
one host take different cell locks".

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-13 11:14:37 -03:00
Daniel Hilst 6c9e905373 Merge master into fix/openeuler-ppc64le-net-dns
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-09 10:40:43 -03:00
Daniel Hilst 506da9cb9f fix(xcat-dep): an aarch64 build on an x86_64 host deploys to the x86_64 cell
target_profile() took the rpm architecture of an EPEL target from the build
host, so alma+epel-10-aarch64 built on an x86_64 host reported arch=x86_64.
target_cell() then resolved to rh10/x86_64, and the deploy would have replaced
the x86_64 cell of the published repository with aarch64 rpms. The same answer
reported forcearch=0, which left the emulated build with the native step
timeout.

The architecture now comes from the target name, which is what names the rpms,
and a target whose architecture differs from the host is a cross-build. mock
already applies --forcearch to such a target, so nothing else has to change for
the build itself to work.

epel_target_profile() in MockBuildUtils carries the decision, and
t/aarch64_cross_build.t calls it. The test pins the answer for every target that
builds today, so the change cannot move one of them, and its two aarch64
assertions fail against the previous behaviour.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-09 06:35:51 -03:00
Daniel Hilst 5213e5fe8d fix(xcat-dep): mock_chroot_uid ignores a chrootuid set after an include
mock_chroot_uid parsed the mock configuration files itself and read each
include() after the file that names it. A chrootuid set after an include
lost to the value in the include, so mockbuild-perl-packages.pl gave the
result directories to a uid mock does not build as.

mock_chroot_uid now asks mock's own loader, mockbuild.config.load_config,
for chrootuid. It fails with a clear message when mock is not installed.
mock_result_dirs takes the configuration and gets the uid from
mock_chroot_uid, so the caller cannot pass a uid from another source.

native/mock-chroot-uid.t returned 1000 instead of 1001 before this change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-07 13:52:06 -03:00
Daniel Hilst 2a1762b22c fix(xcat-dep): the perl builder gives mock result directories it cannot write
perl-Net-DNS is an owner in the openEuler 24.03 ppc64le catalog, so
mockbuild-all.pl builds it with mockbuild-perl-packages.pl. That script runs as
root and creates the srpm, restamp-srpm and rpm directories it gives mock as
--resultdir. mock 6.8 reloads its uid manager from chrootuid, which
openeuler-24.03-ppc64le.cfg sets to 1000, and opens state.log, build.log and
root.log in --resultdir as that uid. root creates those directories mode 0755
with umask 0022, so mock cannot open a log in them and fails in resetLogging
before the build starts.

MockBuildUtils::mock_chroot_uid reads the uid from the configuration mock reads.
mock_result_dirs creates the three directories owned by it. A configuration that
names no chrootuid keeps the uid that runs mock, which is mock's own default, so
every other target is unchanged.

perl-Crypt-Rijndael, perl-IO-Stty and perl-Net-Telnet are owners on the same
target and build from a committed source rpm, so restamp-srpm has the same
boundary and is covered too.

t/perl_builder_mock_result_permissions.t fails 6 of its 14 checks without this
change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-07 12:37:49 -03:00
Daniel Hilst 5d3fcfe906 fix(xcat-dep): the openEuler ppc64le native prerequisites cannot write their logs
Every xcat-dep-build-openeuler24.03-ppc64le build fails at the first native
prerequisite:

  PermissionError: [Errno 13] Permission denied:
    .../native-results/procenv/state.log

mock 6.8 reloads its uid manager from chrootuid ("fix: reload uidManager with
chrootuid/chrootgid from config"), so mock now creates --resultdir and opens its own
state.log, build.log and root.log there as chrootuid, which the openEuler ppc64le
overlay sets to the catalog's build_uid. mockbuild-all.pl creates those directories
as root, mode 755, so mock cannot open a log in them and dies in resetLogging before
the build starts. It is not specific to the shared filesystem: the same failure
reproduces on /tmp.

make_native_path gives every directory mock writes the native build gid and makes it
group writable, and MockBuildUtils::native_owner_command runs the step under setpriv
--regid with a 0002 umask, so what the step creates below those directories inherits
both. The uid a step builds as now comes from the catalog's build_uid instead of the
step id, which also builds xnba-undi as root, as its own declaration says.

t/openeuler_native_result_permissions.t fails five of its six assertions without this
change. native/openeuler-power-inputs.t fails too, with "mock: [Errno 13] Permission
denied: .../native-results/native-leaf/state.log", but only on ppc64le: its native
owner section skips 52 of its assertions on x86_64, which is the architecture the
GitHub workflow runs on. The unit test is what keeps the fix covered there.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-07 10:15:49 -03:00
Daniel Hilst 63784cfbee test(xcat-dep): nothing proves a native dep builder can write its mock result directories
ipxe-xcat/mockbuild.pl runs as root and calls make_path on $work_dir/srpm
and $work_dir/rpm, then gives each one to mock as --resultdir. The native
openEuler overlay sets chrootuid to the catalog's build_uid and chrootgid to
the native build gid, so mock reloads to that uid and opens state.log,
build.log and root.log in those directories. A root-made directory with the
default umask is root root 0755 and mock cannot write them. grub2-xcat,
ipmitool-xcat, syslinux-xcat and goconserver create their result directories
the same way.

What keeps those directories writable is the step wrapper, not the builder:
native_owner_command gives the step the native build gid and umask 0002, so
every directory the builder creates below it is group writable. No test
measured that, so removing either one is silent.

Move native_owner_command into MockBuildUtils so a test can call it in
process, and assert the wrapper carries setpriv --regid 1000,
--clear-groups and umask 0002, that setpriv precedes the umask and the umask
precedes the builder, and that the overlay is still bound over the target
config so chrootuid stays as the catalog declared it.

This commit is the move and the test only. Five of the six assertions fail
here, because the gid and the umask arrive in the next commit.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-07 10:04:41 -03:00
Vinícius Ferrão a5346a21a7 Clarify native repository finalization and publication comments 2026-09-29 00:11:13 -03:00
Vinícius Ferrão 882ca33693 Fix openEuler repository finalization and manifest selection
Exclude native cells from cross-architecture Genesis finalization. Add the missing 24.03 SP1 manifest and expose repository signing for direct validation.
2026-09-29 00:03:57 -03:00
Vinícius Ferrão 5a625e94dd Merge master into openEuler support 2026-09-28 23:56:29 -03:00
Daniel Hilst 8823065ed9 fix(xcat-dep): publish and finalize take locks of cells they do not own
The apt publish took only the run lock of the host arch, and then read
the staging of every expected arch. A ppc64el run could refill its
staging while the publish assembled from it.

Finalize ran on one host and took the cell locks of both arches. If it
died, only that host could reclaim the locks of the other arch's cells,
and the next builds of those cells waited on them and failed.

A publish now takes the run lock of every expected arch, in name order,
before the publish lock, and waits for them up to --publish-lock-wait.
--finalize-arch limits finalize to the cells of one arch: it writes,
locks, re-indexes and verifies only those, and reads the other arches.
Without the option, finalize writes both arches as before.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-28 11:33:20 -03:00
Daniel Hilst bd7312690d Merge master into fix/repo-lock-force-unlock-race
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-28 08:41:19 -03:00
Daniel Hilst 429c573626 fix(xcat-dep): per-arch dep builds share one repository lock
The per-arch runs of one dep build share --repo-dep and each took
<repo-dep>/.lock. The first run won and the others died, so the
pipeline passed --force-unlock. That option removed any lock it found:
a rerun of the same refs could take a cell from a run still writing it,
and common recovery could remove the staging tree of a live publisher.

mockbuild-all.pl now takes XCAT::NFSLock locks: <output>/.lock, one
<repo-dep>/rh<N>/.<arch>.lock per target, and .common-publish.lock while
it recovers or publishes common. --finalize-xcat-dep locks the cells it
rewrites. --try-unlock-timeout N replaces --force-unlock. A run that is
not a dry run recovers an interrupted common publication when no other
run holds the common lock.

sbuild-all.pl takes its per-arch run lock and its apt publish lock as
XCAT::NFSLock locks instead of flock, which fails on the shared tree.

createrepo_c runs without --database. SQLite needs locks, which a client
of an NFS re-export cannot take.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-26 08:39:49 -03:00
Vinícius Ferrão f8f77db1d6 refactor(xcat-dep): share the mock config resolver
mockbuild-all.pl finds the mock config by its file in /etc/mock, and
knows that /etc/os-release says almalinux where mock names the file
alma. Move that resolver into MockBuildUtils, with the config directory
as an optional argument, so a per-package builder can use it. The
behavior of mockbuild-all.pl does not change.
2026-09-25 02:24:42 -03:00
Vinícius Ferrão b89dc6fa46 refactor(build): share repository target inference
Move repository path mapping into MockBuildUtils so callers can use it directly. Keep the openEuler and EL target rules unchanged.
2026-09-24 23:59:07 -03:00
Vinícius Ferrão 724602f485 fix(openeuler): integrate current dependency build and signing paths
Merge current master into the openEuler dependency branch. Preserve native
inputs and publisher signatures with the upstream timeout and keyring
helpers. Use the native repository path when carrying skipped builds.

Cover signed carry-over and mixed publisher/build-key verification.
2026-09-22 19:33:13 -03:00
Vinícius Ferrão 0c0dfb787e feat(openeuler): build native dependency packages 2026-09-21 18:23:51 -03:00
Daniel Hilst 1d95b31285 Merge branch 'master' of xcat2/xcat-dep into fix/mockbuild-skip-perl-gate
master added the per-cell architecture rule (rpm_arch, rpm_in_cell) after
this branch started, so the two sides collide in three places.

The MockBuildUtils and t/mockbuild-all.t import lists take both sets of
names. Neither side removes a name the other needs.

MockBuildUtils.pm now held two definitions of rpm_arch, one from each
side, and Perl kept the later one. master's definition stands: it reads
the header of a file and falls back to the name suffix otherwise, which
is what its own tests and rpm_in_cell need. The branch definition is
removed. carry_over_rpms takes rpm_arch as an argument, so it keeps its
own architecture gate and its own message.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-11 19:13:42 -03:00
Vinícius Ferrão 81205a1c81 fix(mockbuild-all): keep the published rpms of a skipped builder
Each run collects the rpms it built into its run repository, and deploy
stages the cell from that repository and gates it on the whole manifest,
which a skip run cannot satisfy: with --skip-perl there are no perl
packages, the gate reports them missing, and the deploy fails after the
build succeeded. The gate is right to check the whole manifest, since the
flags describe what this invocation built and not what the cell may lack.

After collection, the run repository now takes the binary rpms a skipped
builder published in the cell: whole builds, so subpackages the manifest
does not name stay too; only builds whose source package the target
manifest still names, so a dropped package is not republished; and only
builds of which the run carries no member yet, so generations of one build
never mix. The bump check, createrepo, the tarball and the deploy gate
then see the same complete set. The carry-over stops the run rather than
publish a partial or doubtful set: an rpm in the cell whose header cannot
be read, apart from the OpenEmbedded Genesis family that is pruned by
name, a member of a selected build the signing key did not sign, by signer
id and by rpmkeys --checksig, or whose digests do not verify when no key
is configured, a member of another architecture than the cell or noarch,
or a package published at more than one version. A package that was never
published is still reported missing, and a full run is unchanged. The
zero-artifact check applies only when a builder ran, so a run that skips
both package builders reaches the deploy.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-10 01:12:20 -03:00
Vinícius Ferrão 030259d7f6 fix(mockbuild-all): keep rpms of another architecture out of a target's cell
collect_rpms copied every binary rpm a builder produced. The syslinux builder
also produces syslinux, syslinux-extlinux and their debug rpms for the chroot
it runs in, so a forcearch target that builds the noarch boot loaders in the
native x86_64 chroot would have published x86_64 rpms in the riscv64 cell.
The completeness gate checks names and pins only, so it would have passed.

Keep an rpm only when it is noarch or carries the cell's architecture, read
from the rpm header. The rule lives in MockBuildUtils as rpm_in_cell.
2026-09-08 17:19:40 -03:00
Daniel Hilst 1e9ec56bdc feat(xcat-dep): --install-deps makes a build host able to run the script
Two CD runs died at compile time inside XCAT::BuildUtils because a builder was
missing a Perl module the script loads: perl-File-Slurper on xcat-master-ub and
perl-IPC-Cmd on xcat-master-ppc. Both surfaced as "Can't locate ... in @INC" in
the middle of a build, and both were fixed by hand -- so the next unprovisioned
host fails the same way, and BUILD.md's install line can drift from what the code
actually requires.

--install-deps installs this host's prerequisites and exits: the toolchain plus
the modules, through dnf or zypper as the host's ID dictates. It then LOADS each
module and fails naming any that is still missing, rather than trusting the
package manager's exit code -- a package that installs cleanly but leaves the
module unusable is exactly the failure this exists to prevent.

The list and the command are pure functions in MockBuildUtils, so the decision is
unit-tested (package sets per family, the right installer non-interactively, and
the probe reporting only what genuinely cannot be loaded); the side effect stays
in the caller. Run on xcat-master and xcat-master-ppc: both report every module
present. xcat-master-suse is unreachable and still needs it.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-27 15:29:58 -03:00
Daniel Hilst 9480dfe780 feat(xcat-dep): EVR-constraint gate + rpmkeys checksig + repo_gpgcheck
Three review follow-ups on the repo validation gate:

1. Full EPOCH:VERSION-RELEASE validation. The gate compared only %{VERSION}, so
   xCAT-genesis-base=2.* accepted a pre-2.18 (2.17.x) genesis even though
   xCAT-genesis-scripts Requires >= 2:2.18.0, and it could not enforce release
   floors like perl-IO-Stty >= 0.04-5. Manifest pins now also accept an EVR
   constraint (>=, >, <=, <, = followed by [epoch:]version[-release]); the built
   rpm's full EVR is compared with rpm's own algorithm (rpm.vercmp via the lua
   binding, injected into the pure evr_cmp, which composes epoch/version/release).
   genesis-base is pinned >= 2:2.18.0 and perl-IO-Stty >= 0.04-5. rpm_evr also
   catches release-level stale-artifact accumulation that rpm_version (VERSION
   dedup) missed.

2. RPM-native crypto verification. The per-rpm gate extracted the header signer
   id but did not verify digests/signatures. It now also runs `rpmkeys --checksig`
   against an isolated keyring holding only the signing key (exported from the gpg
   home), so every rpm's header/payload digests AND the signature-by-this-key are
   cryptographically verified; the signer-id origin check is kept alongside.

3. repo_gpgcheck. The generated xcat-dep.repo set only gpgcheck=1; add
   repo_gpgcheck=1 (mirroring gpgcheck) so clients enforce the detached
   repomd.xml.asc signature that sign_and_index_repo already produces.

Validated: unit tests for parse_evr/evr_constraint_ok (rpm's real vercmp; the
reviewer's 2.17.9-rejected, 0.04-4-rejected, epoch-enforced cases) + checksig
verdict; and `--verify-repo` over a real signed rh8/x86_64 cell passes
(12 packages EVR-satisfied, every rpm checksig-verified).

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-21 20:53:08 -03:00
Daniel Hilst ef966fd95b feat(xcat-dep): arch-array cross-arch finalize; verify every rpm signature
Two review follow-ups:

- Cross-arch genesis matrix is now driven by a single @GENESIS_ARCHES array
  (arch -> xCAT tarch) in MockBuildUtils. finalize_xcat_dep discovers, gates, and
  N-way cross-copies over that list, so adding an arch later (aarch64, riscv64) is
  one entry there plus wiring its repo root. No behaviour change for the current
  x86_64/ppc64le pair (tests unchanged + a contract assertion on the array).

- PR #62 review #4: the repo completeness gate verified only the repomd.xml
  signature. It now ALSO verifies every binary rpm's header signature is by the
  configured signing key -- resolve the key's accepted id set (primary + subkey
  ids) and check each rpm's RSAHEADER/DSAHEADER pgpsig key id, failing on any
  unsigned or foreign-signed rpm. Runs per-target in deploy_target and per-cell
  after --finalize-xcat-dep. A signed repomd over an unsigned rpm otherwise passed
  the gate yet DNF rejects the package at install. Added pure fixtures.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-21 19:01:01 -03:00
Daniel Hilst cbb9f4ebfa fix(xcat-dep): finalize cross-arch genesis in both directions
PR #62 review #2: finalize_xcat_dep() discovered OS dirs by grepping for an
x86_64 subdir under the x86_64 repo, so a ppc64le-only <os> (an rh<N> that built
for ppc but has no x86_64 sibling) was never iterated -- finalize never
cross-populated that cell's x86_64 genesis and still exited 0.

Discover the union of <os> dirs from both arch repos and require both arch peers
for every one, so an x86_64-only AND a ppc64le-only cell both die with a named
error instead of passing unnoticed. Add a symmetric fixture for the ppc64le-only
case (mirrors the existing x86_64-only peer test).

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-21 18:50:45 -03:00
Daniel Hilst 5addcaa976 fix(xcat-dep): drop host-install smoke; fix ppc mock-root collision
PR #62 review raised two build-side problems:

1. The child builders installed each freshly built RPM onto the build host
   ("dnf -y install" + a run smoke). Because mockbuild-all builds el8/el9/el10
   on one host, this installs a foreign-EL RPM into the host RPM database and
   corrupts it. The real install-and-run verification already happens in the CI
   Test phase (cluster-test.pl boots a matching MN and installs xCAT + the
   freshly built xcat-dep there), so the host-side smoke was redundant. Remove
   the install/smoke step from every builder and the perl aggregate builder, and
   drop the now-dead --skip-install flag (builders, mockbuild-all.pl, and the
   pipeline invocations). The perl builder's --jobs 1 throttle existed only to
   avoid host dnf-lock contention during that install, so it goes too (perl
   packages build in parallel again). Also drop goconserver's now-unused run_rc.

2. build_mock_uniqueext truncated the run id by keeping the LAST 24 chars, which
   for the 7-char "ppc64le" arch dropped the leading EL digit -- so
   alma+epel-{8,9,10}-ppc64le collapsed to the same run part. goconserver
   compiles every EL in the el10 chroot (build_cfg rewritten to -10-), so the
   chroot name is identical across the three ELs and the uniqueext was the only
   thing keeping their mock roots apart: with parallel targets the three ppc
   goconserver builds raced in one root. Keep a readable leading token AND append
   a short digest of the full id so distinct ids always yield distinct uniqueext.
   Moved the helper into MockBuildUtils.pm and added fixtures (distinct per EL on
   a long run id, both arches, determinism).

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-21 18:42:28 -03:00
Daniel Hilst 25dfc3957a feat(build): manifest-driven repo completeness + signature gate, auto-run after build
Adds a real gate on the BUILT per-target repo, using packages-manifest.conf as the
single source of truth, layered so the decision is pure and unit-tested:

- MockBuildUtils::verify_repo_packages(\%expected,\%present) -- pure completeness
  (MISSING / VERSION vs the manifest pins); verify_repo_signature(\%expected,\%observed)
  -- pure signature identity (UNSIGNED / WRONGKEY). Both unit-tested (happy+sad).
- mockbuild-all.pl does the IO and calls both from one sub, verify_target_repo:
  reads the manifest, enumerates the repo via rpm_version, resolves --gpg-key-name to a
  primary-key fingerprint and extracts repomd.xml.asc's actual signer (VALIDSIG), then
  merges the two pure results and dies listing every problem.
- Runs AUTOMATICALLY at the end of deploy_target (after sign+index), replacing the old
  assert_required_deps + inline version-pin loop with one consolidated gate; suppressible
  with --no-verify-repo. Also a standalone build-free '--verify-repo=<repo>' mode (manifest
  from repo_root, gpg from --gpg-key-name/--gpg-home; target derived from the rh<N>/<arch>
  path or --target).

prove t/mockbuild-all.t: 68/68 (was 50). gpg round-trip smoke-tested: right key -> OK,
wrong key -> WRONGKEY, missing .asc -> UNSIGNED.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-12 15:29:02 -03:00
Daniel Hilst 441f13c034 fix(build): address code review — zero-tolerance comment, gpg quoting, manifest-derived required set, testable release bump
Follow-up to the @viniciusferrao review of the EL matrix build:

- Rewrite the stale run_build_steps_parallel comment that still described the
  removed 'tolerate genesis failure' workaround; the code is strict
  zero-tolerance (xcat-core #7696 made buildrpms.pl exit 0 iff it built the
  genesis rpm), so the comment now matches.
- sh_quote the operator-supplied --gpg-key-name at every rpmsign/gpg site
  (was interpolated raw into the shell).
- Derive assert_required_deps' required set from the target's
  packages-manifest.conf section (the single source of truth) instead of a
  second hard-coded list that could drift.
- Move bump_dep_release_suffix into MockBuildUtils (pure, arg-driven) and add a
  File::Temp fixture test (stamp, xcat-core prune, no-Release skip, idempotency)
  -- the paths the review asked to cover. Its temp file now carries hostname+pid
  so the two arch build hosts can't collide on the shared NFS tree.

prove t/mockbuild-all.t: 50/50.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-12 11:41:46 -03:00
Daniel Hilst b2bd440ba0 fix(mockbuild-all): address remaining PR #62 review nits (1, 4, 6)
Follow-up to 40feffc, addressing the nice-to-have / secondary points from @viniciusferrao's review.

1 (over-reach): the --build-number spec walk now PRUNES a nested `xcat-core`/`xcat-source-code`
   checkout under $repo_root, so the legacy nested layout can no longer rewrite an xCAT-core spec
   (e.g. xCAT-genesis-base.spec's dynamic Release). In the normal sibling layout nothing changes.

4 (validate %RELEASE): after the manifest %VERSION pins, when a CD --build-number bump is in effect
   the run now also asserts the bump actually LANDED in each built dep/perl rpm's %RELEASE (genesis
   excluded -- it is intentionally not bumped). Catches a silently un-bumped NVR that a Version-only
   check misses. New MockBuildUtils::rpm_release helper.

6 (--max-parallel a real cap): the perl builder internally forks up to $effective_parallel_builds
   mock jobs, so running it concurrently with the dep builders let live mock builds reach ~2x the
   cap. Run the perl builder in its OWN phase, after the (quick) dep builders -- each phase then runs
   at most $effective_parallel_builds mock builds, so --max-parallel holds, at a small bounded cost.

Tests: 45/45 in t/mockbuild-all.t (rpm_release added).
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-10 12:46:26 -03:00
Daniel Hilst 40feffc8ce fix(mockbuild-all): address PR #62 review (build-number, finalize, run-state, skip-build, goconserver, docs)
Reviewed by @viniciusferrao. Each numbered point below is his; the code changes verify + fix it.

1. --build-number over-reach / dry-run / double-stamp
   - The bump now runs ONLY on a real build: `--dry-run --build-number N` prints what it would
     stamp and writes nothing (previously it rewrote every spec on disk during a dry run).
   - Re-stamping is idempotent AND replacing: a re-run in a reused tree with a different
     --build-number strips the prior .snap<ts>.<n> before applying the new one, instead of
     accumulating a second stamp (…snap57.snap58). Extracted the per-line logic into the
     unit-testable MockBuildUtils::restamp_release_line and covered it in t/mockbuild-all.t.
   (The headline "rewrites xcat-core / xCAT-genesis-base.spec" does not occur in the real layout:
   xcat-core is a sibling of $repo_root, and there is no genesis spec under the dep tree. The
   legacy nested xcat-source-code case remains a non-CD layout; left as a follow-up.)

3. --finalize-xcat-dep idempotency
   - cross_copy_genesis compared only SIGMD5 (content), which is blind to signature + index state.
     It now also treats a same-content-but-UNSIGNED destination rpm as not-up-to-date (new
     rpm_is_signed helper) so a crash between copy and sign heals on re-run.
   - finalize_xcat_dep now re-indexes+signs BOTH repos of a touched pair every run, not only when
     an rpm was copied, so a crash after copy+sign but before createrepo (rpm on disk, absent from
     repomd) also heals.

4. Stale run-state can mask a failed build
   - A real build now wipes its per-target $run_root first (run_id is derived from the deterministic
     commit time, so re-runs reused the same tree). --skip-build keeps the tree; --dry-run writes nothing.
   - mockbuild-perl-packages.pl clears each package's stale status.txt/error.txt BEFORE building, and
     the aggregate now treats the child worker's exit code as authoritative: a package is PASS only if
     its worker exited 0 AND wrote a PASS this run (a stale PASS in a reused log dir no longer counts).

5. --skip-build can publish the wrong artifacts
   - --skip-build now REQUIRES an explicit --target (without it, all three EL targets collected the
     same EL-agnostic roots and cross-published them).
   - Collection is scoped to this target's own per-target $build_root (the same tree a normal build
     populates), not the legacy build-output/list3/list5/list6 dirs.
   - The manifest version-pin validation (and the "no manifest section" guard) now also run under
     --skip-build, so a collection-only publish is validated exactly like a fresh build.

2. goconserver bypassed the CD bump (minimal fix; hermetic rebuild deferred)
   - goconserver/mockbuild.pl gains --release-suffix, appended to its generated `Release: 4.elN`,
     and mockbuild-all.pl passes the CD suffix down -- so goconserver's NVR advances per run like
     every other dep package (an additive publish is no longer a silent no-op on a frozen NVR).
   - Pinned the clone to an immutable upstream commit instead of the moving `master` (0.3.3 is
     unreleased -- newest tag is v0.3.2 -- so a SHA pin is required; clone now fetches by ref).
   - The host build + `go mod tidy` hermeticity concern is a tracked follow-up, not in this change.

7. Docs
   - BUILD.md: --target is a single value, not repeatable; conserver-xcat is built for every target
     (not "not required"). POD: --parallel-targets default is 1 = serial, not "auto".
   - Added a manifest<->docs consistency test (conserver-xcat present in every target section).

(6, --max-parallel not a true global cap, is a documented nice-to-have and is left as a follow-up.)

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-08-10 11:23:04 -03:00
Daniel Hilst e75b56a405 fix(xcat-dep): harden finalize peer requirement + rpm version/identity edges
Follow-up self-review hardening on top of the PR #62 review response:

- finalize_xcat_dep now treats a missing ppc64le PEER repo (not just missing
  genesis rpms) as fatal instead of silently skipping the OS -- in the CD both
  arches build every EL, so a missing peer is an incomplete input that would
  otherwise leave the x86_64 repo without the ppc64 genesis and still exit 0.

- cross_copy_genesis treats an empty SIGMD5 (unreadable rpm) as "cannot confirm
  identical" and refreshes, rather than risking a false up-to-date match when two
  unreadable rpms both return an empty digest.

- rpm_version fails when a directory holds more than one distinct version of a
  package (a stale artifact not cleaned before the build) instead of silently
  returning the first sorted match, which a version pin could pass against while
  the stale rpm still ships. Both arches share a Version for genesis, so a normal
  x86_64+ppc64 pair is a single entry.

t/mockbuild-all.t: +4 cases (30 total) -- missing-peer fatal, rpm_sigmd5 on a
missing rpm, and rpm_version multi-version failure.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-07-28 17:23:39 -03:00
Daniel Hilst ee6524ade5 fix(xcat-dep): address PR #62 review -- finalize/genesis/skip correctness + tests
Review feedback (viniciusferrao):

1. --finalize-xcat-dep no longer succeeds with no genesis rpms and no longer treats
   a shared filename as up to date when the content differs.
   - finalize_xcat_dep now REQUIRES each arch's own genesis rpm for every repo pair
     it processes (a pair with none is a hard FATAL, not a silent exit-0 no-op).
   - cross_copy_genesis compares RPM identity by SIGMD5 (header+payload digest,
     independent of the GPG signature), so a stale rpm that merely shares a basename
     is refreshed instead of being mistaken for up to date.

2. Remove the genesis workaround. xcat-core #7696 is merged, so buildrpms.pl now
   exits 0 iff it produced the genesis rpm; the zero-tolerance check no longer
   ignores a genesis failure when a matching (possibly stale) rpm already exists --
   any failed build step, genesis included, fails the run.

3. Skip modes work. required_pkgs() drops the packages whose builder was skipped, and
   both the version-pin check and assert_required_deps use it, so a clean
   --skip-genesis / --skip-xcat-dep / --skip-perl run no longer fails validating
   packages it deliberately did not build.

4. Tests. The reusable, side-effect-free helpers are factored into MockBuildUtils.pm
   (cross_copy_genesis and finalize_xcat_dep take injected sign/reindex callbacks so
   they carry no gpg/createrepo state) and t/mockbuild-all.t adds focused fixture
   tests for all of the above: skip-mode selection, version-pin globs, SIGMD5-based
   RPM-identity comparison + cross_copy refresh/idempotency, and the finalize
   require-inputs guard. Run with `prove t/`.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-07-28 16:57:35 -03:00