2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-20 14:45:41 +00:00
Commit Graph

28247 Commits

Author SHA1 Message Date
Daniel Hilst cbfd5fb47a Merge pull request #7881 from VersatusHPC/backport-7867-to-2.19
[Backport 2.19] fix(xcat-core): cancelling a build leaves its workers writing the checkout
2026-09-24 12:47:37 -03:00
xcat2-backport-automation[bot] 46e3655297 Merge pull request #7880 from xcat2/backport-7850-to-2.19
[Backport 2.19] fix(otherpkgs): the postscript truncates its syslog output and logs a failed install as installed
2026-09-24 15:25:48 +00:00
Daniel Hilst b62585475a fix(xcat-core): build locks the shared tree refuses to grant
A cancelled build left its lock directory behind on the shared tree, so
every later build of the same checkout waited for a lock whose owner was
gone. The build helper ran each command with a plain fork and killed only
the immediate child, so the shell's own workers survived the cancellation
and kept the tree in use.

XCAT::BuildUtils now runs each command in its own process group, blocks
the cancellation signals across the fork so neither side can miss the
group, and signals the group rather than the pid. It escalates to KILL,
confirms the group is gone, and retains the locks when it is not, so a
lock is never released while a worker can still write.

xCAT-test/unit/builddebs_lock_cancellation.t captures the defect. It
fails without the change.

Backport of #7867 to 2.19.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-24 11:58:27 -03:00
Daniel Hilst bab40d9a1d test(xcat-core): the otherpkgs zypper test deletes the repository in both cases
run_zypper_local_repo extracted six lines of the zypper branch of otherpkgs and
evaluated each one in turn. The branch it measures is an if/else: the repository
is deleted only when the refresh fails. Evaluating the lines separately ran the
delete every time, so the test showed that zypper sd is reachable and never that
a repository which refreshes is kept.

The helper now evaluates the whole branch, from the #use zypper comment to the
apt branch that follows, with pmatch lifted from the same file. The success case
asserts rc=0 and no zypper sd; the failure case keeps its delete assertion.

Flipping the refresh test in otherpkgs to "if [ $? -ne 0 ]" turns both cases
red. The same mutation left the previous helper green, because it never
evaluated that line.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit e19a10396e)
2026-09-24 14:56:56 +00:00
Daniel Hilst 6e8b6b41e0 fix(xcat-core): the otherpkgs bats anchors match more than one block
Four cases in xCAT-test/bats/postscripts_otherpkgs.bats fail on the integrated
tree. extract_shell_if_block reports that the upgrade anchor occurs 4 times and
the url repository anchor occurs 2 times, where 1 is expected.

"if [ $hasyum -eq 1 ]; then" opens the upgrade block and also the yum branch of
the preremove, the install and the postremove blocks. "OTHERPKGDIR_INTERNET"
matches the guard that opens the url repository block and an assignment inside
that block. The earlier helper took the first match and said nothing.

otherpkgs_block now passes NTH and TOTAL through to extract_shell_if_block. The
two upgrade cases take occurrence 1 of 4, so a fifth identical line fails the
test instead of moving it. The two url repository cases anchor on the guard
line itself, which occurs once.

Both blocks the earlier helper took are the blocks the assertions describe, so
no case measured the wrong code. On the integrated tree bats -r xCAT-test/bats
gives 113 ok and 0 not ok. On this branch, where the helper is not yet
hardened, the file gives 18 ok.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit b6e2810860)
2026-09-24 14:56:56 +00:00
Daniel Hilst 74a226b9a2 fix(xcat-core): otherpkgs does not log a failed rpm install or removal
A failed package install through the rpm or dpkg fallback leaves no
record in syslog. The same holds for the four package removal branches
that run after the install. The postscript sets its return code, but a
reader of the node log sees nothing, because the package manager output
goes to the console only when VERBOSE is set.

In xCAT/postscripts/otherpkgs the fallback install block, and the yum,
zypper, apt and rpm removal blocks, set RETURNVAL on a non-zero status
and stop there. Only the three repository install branches send a
message with local4.err.

This change adds the same local4.err message to the five branches that
have none. Each message names the command that ran, as the repository
install branches do.

xCAT-test/bats/postscripts_otherpkgs.bats drives each block with a
package manager that returns a failure. Two cases assert the message is
present, and both fail on the parent commit. Two more assert the
success path still logs "installed." and "removed." alone.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit e058c9afd9)
2026-09-24 14:56:56 +00:00
Daniel Hilst fefced0b49 fix(xcat-core): otherpkgs prints the whole package list on every run
The otherpkgs postscript writes two diagnostic lines for each package
sublist: the split package array with its size, and the detected package
manager. On a list with tens of entries these lines fill the updatenode
output and the node log, and hide the install results.

The two echo commands sit in xCAT/postscripts/otherpkgs, after the
IFS split that builds pkgsarray, and no condition guards them. Every
other diagnostic in the script runs only when VERBOSE is set.

This change puts the two lines in the same "if [ $VERBOSE ]" block the
rest of the script uses.

xCAT-test/bats/postscripts_otherpkgs.bats runs the split and the lines
that follow it. One case asserts no output when VERBOSE is empty, and
fails on the parent commit. A second case asserts both lines are still
printed when VERBOSE is set.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 402a6f4a45)
2026-09-24 14:56:56 +00:00
Daniel Hilst 75fb7a9758 fix(xcat-core): otherpkgs refreshes a zypper repository it did not add
The local otherpkgs repository is written with the alias xcat-otherpkgs$localrepoindex, where
localrepoindex is urlrepoindex plus the array index. Lines 833 and 843 of
xCAT/postscripts/otherpkgs then refresh and delete xcat-otherpkgs$index. With http OTHERPKGDIR
entries present urlrepoindex is not zero, so zypper names a repository that block did not add:
the refresh fails for a repository that exists, and the delete removes another one.

Both lines now use $localrepoindex. The log and the echo of a failed SDK repository add name
$bname, which is what zypper ar used; they said bname without the $.

postscripts_otherpkgs.bats drives the add, the refresh and the delete with zypper shadowed and
urlrepoindex set to 2, and reads the alias back out of the repository file the script wrote.
Against the unfixed script the refresh and the delete name xcat-otherpkgs0 while the file says
xcat-otherpkgs2, and the SDK log carries no repository name.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 73c293f03e)
2026-09-24 14:56:56 +00:00
Daniel Hilst 6d70be73cb fix(xcat-core): otherpkgs writes a trailing space into the generated baseurl
Line 297 of xCAT/postscripts/otherpkgs appends each http OTHERPKGDIR entry as "${dir} ,".
The list is split on the comma alone, so every url keeps the space, and the url repository
block writes "baseurl=<url> " into the yum repository file and "deb <url> " into the apt
source.

The separator no longer carries the space.

postscripts_otherpkgs.bats runs the split and the url repository block and compares the
generated baseurl and deb lines with the url. Against the unfixed script both differ by the
trailing space.

dnf 4.20 strips trailing whitespace from an ini value, and apt splits a source line on
whitespace, so no package manager reads the space today. The generated file is still wrong.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 7bd04f012d)
2026-09-24 14:56:56 +00:00
Daniel Hilst 5f08e3a857 fix(xcat-core): the otherpkgs url repository guard tests a literal string
Line 672 of xCAT/postscripts/otherpkgs reads [ -n "OTHERPKGDIR_INTERNET" ]. The $ is missing,
so the test is on the name of the variable and is always true. The guard cannot select the
case it was written for.

The guard now tests $OTHERPKGDIR_INTERNET.

postscripts_otherpkgs.bats extracts the condition from the script and runs it with the
variable empty and with an http entry. Against the unfixed script the empty case is true.

The block is inert when the variable is empty, because the loop inside it iterates an empty
array, so the run of the postscript does not change. The guard is still wrong.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 70e31f2f15)
2026-09-24 14:56:56 +00:00
Daniel Hilst e3f2afd807 fix(xcat-core): otherpkgs logs a failed package install as installed
In xCAT/postscripts/otherpkgs the success message runs after the branch that records a
non-zero return, not inside an else. A node that fails to install its otherpkgs therefore
reports both "... failed." and "... installed." to syslog, and a reader that greps for the
success line sees a clean install. The same shape covers the four install sites and the four
removal sites.

Each success message now sits in the else branch of the status test.

postscripts_otherpkgs.bats drives the install and postremove blocks with a package manager
that fails, and uses refute_grep to require that no "installed."/"removed." message is sent.
Against the unfixed script both tests find the success message. refute_grep is new in
helpers/shell_source.bash, because bash ignores errexit for a command inverted with "!".

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 42746fae5a)
2026-09-24 14:56:56 +00:00
Daniel Hilst efab86ab9a fix(xcat-core): otherpkgs sends the package manager output to syslog as one truncated message
The otherpkgs postscript passes the whole package manager transaction to logger as a single
message argument. rsyslog escapes every newline to #012 and cuts the message at 8 KiB, which
is where the Failed:, Error: and summary lines sit. A line that starts with -- is also read
as a logger option.

The seven sites in xCAT/postscripts/otherpkgs that log $result now pipe it to logger. logger
without a message argument reads standard input and sends one message per line.

postscripts_otherpkgs.bats drives the upgrade block and the two preremove blocks with logger
and the package manager shadowed, and counts the messages. Against the unfixed script the
three tests report one message where three are expected.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit a603b9d6c2)
2026-09-24 14:56:56 +00:00
xcat2-backport-automation[bot] 1b57120897 Merge pull request #7879 from xcat2/backport-7834-to-2.19
[Backport 2.19] fix(xcat-core): the Ubuntu ppc64le diskful install stops without grub-ieee1275
2026-09-24 14:26:19 +00:00
xcat2-backport-automation[bot] 2d0a2d04d6 Merge pull request #7878 from xcat2/backport-7853-to-2.19
[Backport 2.19] fix(xcat-core): one node's request to the install monitor blocks every other node
2026-09-24 13:59:19 +00:00
Daniel Hilst dde7ebd97e test(xcat-core): an assertion about /run could not tell who wrote there
The error-command test ended with

    [ ! -e /run/testnode-logs.tar ]

meant to show the archive had not gone to the default path. It cannot show that.
The file may exist for reasons that have nothing to do with this test, in which case
the assertion fails while nothing is wrong; and its absence would be equally true if
the override had never worked at all. It answers a question about the host, not
about the run.

The positive assertion above it already carries the proof: the tar shadow writes a
marker, and the test greps for that marker in the path it passed. The output being
there is what shows the redirection went there.

Removing it changes nothing about what the test catches. With the override taken out
of the template, so the archive path is hard-coded again, the remaining assertion
still fails.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit f8618ce746)
2026-09-24 13:57:21 +00:00
Daniel Hilst 87d0955e3e fix(xcat-core): the error-command test writes the log archive to /run
The first subiquity error command redirects into /run/#HOSTNAME#-logs.tar. A
test can shadow tar, but not the redirection: the shell opens that file
whether or not tar runs, so the test writes to the host it runs on. Unprivileged
the open fails and "exit 0" hides it; CI runs as root, where the same line
creates or truncates the file.

The path is read from XCAT_ERROR_ARCHIVE, falling back to the same default, the
way XCAT_ERROR_CONSOLE already does on the next line. An install sets neither
variable and writes where it always did.

The test points the variable inside BATS_TEST_TMPDIR, has the tar shadow emit a
marker so the output can be traced to the file it named, and asserts the default
path under /run was not touched. Reverting the template to the fixed path fails
that case.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit c27ea7ecf3)
2026-09-24 13:57:21 +00:00
Daniel Hilst 654306d2c1 test(xcat-core): the error-command test writes the log archive to /run
The first subiquity error command redirects tar's output into
/run/#HOSTNAME#-logs.tar. The test shadows tar, but the redirection belongs to
the shell and happens whether or not tar runs:

  $ bash -c 'tar() { :; }; ( tar ... >/run/testnode-logs.tar 2>/dev/null; exit 0 )'
  bash: line 1: /run/testnode-logs.tar: Permission denied
  exit=0

Unprivileged the open fails, "exit 0" swallows it and the test passes. CI runs
as root, where the same line creates or truncates that file on the host.

The archive path now comes from the environment, the way XCAT_ERROR_CONSOLE
already does in the same block, and points inside BATS_TEST_TMPDIR. The tar
shadow emits a marker so the test can tell the output reached the file it
named, and a second assertion says the default path under /run was not touched.

The new case fails until the template reads that variable.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit ac63d37843)
2026-09-24 13:57:21 +00:00
Daniel Hilst b5586111fa test(xcat-core): the subiquity error-command test is written as a Perl program
ubuntu_subiquity_error_commands.t measures shell. It parses the error-commands
block out of compute.subiquity.tmpl, renders each item, writes a wrapper that
shadows nc, tar and tail, and shells out. The Perl adds nothing the shell
cannot state, and the reader follows two languages to reach two assertions.

The test moves to xCAT-test/bats, which the xcat_test workflow already runs. It
keeps what it proved: the error commands return instead of waiting for a
collector an unattended install does not have, and they write the end of the
curtin log to the console the installer names. An error-commands block that
stops matching fails the test instead of covering nothing.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit d5fd9027df)
2026-09-24 13:57:21 +00:00
Daniel Hilst 51cb875be9 test(xcat-core): a failed extraction in the error-commands test stops the whole suite
ubuntu_subiquity_error_commands.t called BAIL_OUT at both places where
its extraction of the error-commands block stopped matching. prove stops
every remaining file on a bail-out, so a change to the template that
breaks the regex in this file also hides every test that would have run
after it. die is just as loud and costs only this file.

Three comments the branch added also carried the bug report: the test
header, the template comment and the Template.pm comment each traced the
failure from the error command to the provisioning timeout. Each now
states the constraint the reader cannot see in the code.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit db820cfcc0)
2026-09-24 13:57:21 +00:00
Daniel Hilst c3bbe8b305 fix(xcat-core): a failed Ubuntu install stops until the provisioning timeout
When a Subiquity install fails, the node stays up with no disk or network
activity and reports nothing. The management node sees only the last progress
line the installer printed, and the case fails on the provisioning timeout
rather than on the error.

The error-commands entry in compute.subiquity.tmpl pipes the log archive into
"nc -l 8080". Subiquity waits for every error command to return, and that
listener returns only when a collector connects, which an unattended install
has none of.

The archive now goes to /run on the installer, and a second command prints the
end of the curtin log to the console, which the management node records with
the rest of the install. XCAT_ERROR_CONSOLE names that console, so the command
can be driven outside the installer.

ubuntu_subiquity_error_commands.t runs the template's own error commands with
nc, tar and tail replaced. Without this change the first assertion times out.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit c98e868cb3)
2026-09-24 13:57:21 +00:00
Daniel Hilst 46f1d4f2f7 test(xcat-core): a failed Ubuntu install waits for someone to collect its logs
The Subiquity template offers the installer logs with "nc -l 8080" in
error-commands. Subiquity waits for every error command to return, and that
listener waits for a collector an unattended install never has, so a failed
install stops there until the provisioning timeout resets the node.

The test runs the template's own error commands with nc, tar and tail replaced,
and requires that they return and that they write the end of the curtin log to
the console the caller names. Both assertions fail before the fix: the first
times out.

Evidence: reg_linux_diskfull_installation_flat on Ubuntu 24.04 ppc64le, cluster
xcat25. The node wrote no disk block and sent no packet for 18 minutes with the
console at "acquiring and extracting image from cp:///tmp/.../mount". Port 8080
was open; one connection to it released the install and the console then
reported the error.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 19a7a41572)
2026-09-24 13:57:21 +00:00
Daniel Hilst 30265c2d12 fix(xcat-core): the Ubuntu ppc64le diskful install stops without grub-ieee1275
A diskful install of Ubuntu on a ppc64el node runs to the bootloader step and
stops. curtin reports "dpkg-query: package 'grub-ieee1275' is not installed"
from dpkg-reconfigure, and the node never reaches the disk it installed.

ubuntu_subiquity_apt_config in xCAT-server/lib/perl/xCAT/Template.pm writes
APT::Install-Recommends "false" for every architecture. curtin installs a
bootloader package of its own for UEFI and for s390x only, so on a PReP
machine grub-ieee1275 reaches the target only as a recommended package of the
kernel image, and that setting removes it.

The apt block now keeps the recommended packages on ppc64el, online and
offline, and is unchanged on every other architecture.

ubuntu_subiquity_pkglist.t renders the block for osarch ppc64el and requires
that it does not disable the recommended packages. Both assertions fail
without this change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 5d0f6fc50d)
2026-09-24 13:57:21 +00:00
Daniel Hilst f5108762cb test(xcat-core): the Ubuntu ppc64le install drops the bootloader package
The Subiquity apt configuration sets APT::Install-Recommends "false" for every
architecture. On ppc64el the target gets grub-ieee1275 only as a recommended
package of the kernel image, so the setting removes it and curtin fails.

The test renders the apt block for osarch ppc64el, online and offline, and
requires that it does not disable the recommended packages. Both assertions
fail before the fix.

Evidence: reg_linux_diskfull_installation_flat on Ubuntu 24.04 ppc64le,
xcat-core-devel-ubuntu-cd build 122, cluster xcat25. curtin-install.log:
"dpkg-query: package 'grub-ieee1275' is not installed", from
['unshare', '--fork', '--pid', '--mount-proc=/target/proc', '--', 'chroot',
'/target', 'dpkg-reconfigure', 'grub-ieee1275'].

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit df5c83c0bf)
2026-09-24 13:57:21 +00:00
xcat2-backport-automation[bot] 58acf4b9dc Merge pull request #7877 from xcat2/backport-7851-to-2.19
[Backport 2.19] fix(xcatdsklspost): updatenode leaves /xcatpost populated when site.cleanupdiskfullxcatpost is set
2026-09-24 13:54:30 +00:00
Daniel Hilst da14ab03bb fix(xcat-core): a queued install monitor request waits for the next unrelated node
The install monitor holds the later connections for a node whose handler
is still running, and forks the next one when it reaps that handler.
SIGCHLD is what brings the parent back to look: it interrupts the accept.

A handler can exit after the parent checks its queue and before the
accept begins. The signal is then handled where there is no accept to
interrupt, and the parent blocks in accept with a connection already
queued and ready to run. That connection waits until some other node
calls in. A single node retrying on its own waits until it times out.

do_installm_service now waits through wait_for_installm_connection, which
selects on the listening socket. The wait is bounded by
$installm_wakeup_seconds while connections are queued, so the parent
looks at its queue again instead of waiting for another client. An idle
monitor with an empty queue still waits without a bound, because a
handler that exits then leaves nothing to do.

The new case asserts the wait ends on its own bound with nothing to
accept, and ends at once when a connection is already there. It fails
when the bound is ignored.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 5ac62ebb51)
2026-09-24 13:26:27 +00:00
Daniel Hilst 1ae80c567d test(xcat-core): nothing covers the order of a node's requests when one is lost
The install monitor answers a node's requests in the order they arrived.
Two ways to lose that order had no test.

The first is a queued client that gives up. The parent holds the later
connections for a busy node unread, so a client that closes its socket
must not let the request behind it overtake the request that is running.
The new case runs one request, queues two more, drops the middle client,
and asserts the last request starts after the running one ends. It fails
when the per-node queue is removed.

The second is a fork that fails. The monitor then answers the node
itself, in line. The new case makes one fork fail and asserts the request
is answered and that the node's next request starts only after it. It
fails when the fallback drops the connection instead.

The file also asserts the lifted service holds no literal /var/run path.
Every access to the pid file goes through $installm_pidfile, so pointing
that variable at the scratch tree redirects all of them, and a path
written out again inside the routine would reach the host file.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 5f5ebcde7e)
2026-09-24 13:26:27 +00:00
Daniel Hilst 92e976eae4 fix(xcat-core): the install monitor concurrency test fails on a rounded time
xcatd_install_monitor_concurrency.t failed about one run in five. The
assertion "the node is released only after the destiny advance finished"
compares the time the test read "done" from the socket against the time
the plugin stand-in recorded when it finished. The stand-in wrote that
time with %.3f, which rounds up, so a recorded time can be later than the
moment it was taken. The test then failed on the rounding and not on the
order:

    '1790220468.11892' >= '1790220468.119'

The events file now holds whole microseconds from gettimeofday, and the
comparisons read the same clock. gettimeofday rounds nothing.

Each case also writes an events file of its own. A handler forked by one
case outlives the monitor that forked it, so it could append to the case
that runs next.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit ee41e98751)
2026-09-24 13:26:27 +00:00
Daniel Hilst 4e45d3ca0b fix(xcat-core): the install monitor orders a node's requests in the children
The ordering between two requests for one node was a chain of pipes: each child
held the write end and the next child for that node read the previous one to end
of file. End of file there means the previous process is gone, not that its work
finished, so a child that died released the one behind it -- and released the
wrong one, because each child waits on its immediate predecessor rather than on
the request actually in flight. The fork-failure path closed the predecessor and
served the request in line without waiting at all.

The parent now owns the order. %installm_busy names the handler serving a node,
%installm_queue holds the connections accepted for that node meanwhile, and the
next one is forked when the handler ahead of it is reaped. A handler that dies
cannot release the one behind it, and the fork-failure path has nothing to fall
back over, because it is reached only when the node has no handler.

Three other changes the same design makes possible or necessary:

  - The answer to a destiny advance now follows the advance. Every other request
    is still answered before it runs, because its result does not change what
    the node does next. Holding one node costs no other node anything now, and
    it lets the node retry an advance whose handler died -- which the old order
    could not, because "done" was already on the wire.
  - The monitor drains its handlers before it exits. Without this a restart
    orphans them into the systemd service cgroup, where anything still running
    at TimeoutStopSec is killed after its answer was already sent.
  - SIGCHLD is caught, so a handler exiting interrupts accept and the parent
    comes back to look for a connection queued for that node.

The pid file path is a variable, so the test can point the lifted routine at a
scratch file instead of the one a restarting xcatd reads to tell the running
monitor to let go of the port.

xcatd_install_monitor_concurrency.t grew the cases for all of it. Four
mutations, each caught by one assertion: forking every connection at once turns
the ordering case red; answering a destiny advance before the plugin turns the
release case red; removing the drain turns the stand-down case red; and leaving
the emptied queue entry behind turns the leak case red. The full unit suite is
194 files, 5662 tests, green.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit b2432c048d)
2026-09-24 13:26:27 +00:00
Daniel Hilst 684d060a01 fix(xcat-core): xcatd_install_monitor_concurrency.t passes when the file it reads is missing
xcatd_install_monitor_concurrency.t called plan skip_all when xCAT-server/sbin/xcatd was absent, so a checkout that lost
the file reported 0 tests and exit 0. A test that cannot fail measures nothing.

Die instead, which is what makentp_ntp_deps.t already does for setupntp.

With xCAT-server/sbin/xcatd moved aside the file now exits 2 and prints "xcatd not found at <path>";
before this change it exited 0 and printed "1..0 # SKIP xcatd not found at <path>". With the file
present the test passes either way.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 36a3aee1a6)
2026-09-24 13:26:27 +00:00
Daniel Hilst e445ec435c fix(xcat-core): one node's request to the install monitor blocks every other node
The xcatd install monitor serves every installing node from one accept loop. It
accepts a connection, resolves the peer to a node and dispatches the request in
line, so nothing else is accepted until that request returns. On a management
node holding three connections that send nothing, a second node waited 5.7
seconds for the monitor's greeting.

do_installm_service in xCAT-server/sbin/xcatd calls plugin_command directly in
every branch. The per-request fork that once stood there is commented out with
the note that the node must be blocked, because 'nodeset next' and
'installstatus' for one node write the same chain row.

The monitor now gives each connection its own child and keeps that ordering per
node: the child for a node reads a pipe left by the previous child for the same
node, and starts when that pipe reaches end of file. Live children are capped at
64 and the rest wait in the listen backlog, the parent reaps them, and a child
that dies no longer takes the monitor with it. A per-node lock file was rejected
because it needs a new directory and gives no arrival order; letting the parent
wait for the busy node was rejected because it blocks the accept loop again.

xcatd_install_monitor_concurrency.t lifts do_installm_service out of the program
and drives it with real clients. Without this change the second node waits 5.7
seconds and the monitor does not survive a request that kills its handler.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 9e99dc2580)
2026-09-24 13:26:27 +00:00
Daniel Hilst 2c519d0a3b test(xcat-core): one node's request to the install monitor blocks every other node
The xcatd install monitor accepts a connection, resolves the peer to a node and
dispatches the request in line. Nothing else is accepted until that request
returns, so a node whose 'nodeset next' takes three seconds costs every other
installing node three seconds. A request that kills the process serving it takes
the whole monitor down with it.

do_installm_service in xCAT-server/sbin/xcatd is one process with one accept
loop. Every branch calls plugin_command directly. The per-request fork that once
stood there is commented out, because two requests for one node write the same
chain row and must not overlap.

This commit adds the test only. xcatd_install_monitor_concurrency.t lifts
do_installm_service out of the program, runs it on a port of its own against
stand-in plugins, and drives it with real clients: one node holds a three-second
request, a second node times its greeting, two requests for one node are checked
for overlap, and one request kills the process that serves it.

The test fails on this tree. The second node waits 5.7 seconds for its greeting,
and the monitor does not survive a request that kills its handler.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 574b3590db)
2026-09-24 13:26:26 +00:00
Daniel Hilst 41cb0b3f9d fix(xcatdsklspost): the diskful cleanup deleted a diskless node's postscripts
site.cleanupdiskfullxcatpost names the node type it applies to, and site.5.rst
says "on the diskfull nodes". xcatdsklspost serves every type: updatenode calls
it for a diskless or statelite node as well, and the site value is one row that
reaches all of them. With cleanupdiskfullxcatpost=yes and cleanupxcatpost=no,
append_xcatpost_cleanup still appended the delete for those nodes.

The diskful branch now reads NODESETSTATE from the generated mypostscript and
appends nothing for netboot or statelite. That is the signal remoteshell,
hardeths, configeth, otherpkgs and servicenode already use for this question,
and mypostscript.tmpl exports it.

cleanupxcatpost is unchanged. It names no node type and keeps applying to every
one, which xcatdsklspost_xcatpost_cleanup.bats now asserts so a guard added to
the wrong branch shows up.

Four cases cover it: a netboot node and a statelite node keep their postscripts,
a diskful node is still cleaned, and cleanupxcatpost still empties a netboot
node. The first two fail against the parent commit.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 9c2e733b99)
2026-09-24 13:22:06 +00:00
Daniel Hilst 40fec5d397 fix(xcat-core): postscript_heredoc_embedding.t passes when the file it reads is missing
postscript_heredoc_embedding.t called plan skip_all when xCAT-server/share/xcat/install/scripts was absent, so a checkout that lost
the file reported 0 tests and exit 0. A test that cannot fail measures nothing.

Die instead, which is what makentp_ntp_deps.t already does for setupntp.

With xCAT-server/share/xcat/install/scripts moved aside the file now exits 2 and prints "<scriptdir> not found";
before this change it exited 0 and printed "1..0 # SKIP <scriptdir> not found". With the file
present the test passes either way.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit fdc96de015)
2026-09-24 13:22:06 +00:00
Daniel Hilst 181050ea43 fix(xcat-core): a diskfull install runs a post script bash cannot parse
Every diskfull install stopped in the installer. The node installed the OS and
answered ping, but no postscript ran, so remoteshell never wrote the root key
and the management node got "Permission denied (publickey,password)". The node
stayed at status powering-on and reinstalled in a loop.

append_xcatpost_cleanup in xCAT/postscripts/xcatdsklspost writes the cleanup
with a here-document whose delimiter is EOF, so the file holds a line "EOF".
post.xcat, post.xcat.ng, post.xcat.rhels10, post.debian and the two s390x
scripts embed the whole file with "#INCLUDE:<path>#" inside "cat
>/opt/xcat/xcatdsklspost << 'EOF'". That line ends the outer here-document
early, and the remaining 890 lines of xcatdsklspost become shell code in the
generated install script. bash reports a syntax error and curtin fails the
late-command that runs it.

The here-document now ends at XCATPOST_CLEANUP, and a comment states the
constraint the file is under.

postscript_heredoc_embedding.t assembles each embedding and parses it. It fails
on the six install scripts without this change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit b2d19b4afe)
2026-09-24 13:22:06 +00:00
Daniel Hilst a06ba8e46d test(xcat-core): cover the here-document that embeds a postscript
The install-time post script embeds xcatdsklspost, xcatinstallpost and
xcatpostinit1 with "#INCLUDE:<path>#" inside a here-document. The template
copies each file verbatim, so a line in the postscript that equals the
here-document delimiter ends that here-document early, and the rest of the
postscript becomes shell code in the generated install script.

Nothing measured that. The new test assembles every such embedding the six
post.* install scripts declare, and asserts that bash parses the result and
that no line of the embedded file equals the delimiter.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 0183628fa0)
2026-09-24 13:22:06 +00:00
Daniel Hilst 070fc3ca69 fix(xcatdsklspost): updatenode leaves /xcatpost populated when site.cleanupdiskfullxcatpost is set
An administrator sets site.cleanupdiskfullxcatpost, deploys a diskfull node, and
/xcatpost is empty. The next updatenode run downloads the postscripts again and
leaves them there. /xcatpost is mode 0755 and most of what lands in it is
world-readable, so material the administrator was told is gone comes back on
every maintenance run and on every reboot.

xcatdsklspost is the script that repopulates /xcatpost on all of those paths, and
it reads only CLEANUPXCATPOST. CLEANUPDISKFULLXCATPOST reaches the node in the
same mypostscript, exported by the site table, and no code reads it. Only
xcatinstallpost does, and that runs once, at install.

Read it in append_xcatpost_cleanup with the rule xcatinstallpost uses: remove the
postscripts when the run returns 0, keep updateflag.awk, and leave everything in
place after a failed run so the node can be examined.

xCAT-test/bats/xcatdsklspost_xcatpost_cleanup.bats captures this. Three of its
six tests fail on the previous commit.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 873ad1d41c)
2026-09-24 13:22:06 +00:00
Daniel Hilst cc49558f77 test(xcatdsklspost): cover the /xcatpost cleanup after an updatenode run
The site table has two attributes for the same directory and only one of them is
covered: nothing pins what xcatdsklspost appends to mypostscript for
site.cleanupdiskfullxcatpost, on the path every updatenode run takes.

Drive append_xcatpost_cleanup against a scratch /xcatpost, run the mypostscript
it writes, and assert on the directory that comes back: the postscripts are gone
after a run that succeeds, updateflag.awk stays, and a run that fails keeps
everything. Add refute_grep to the helpers, because a "! grep" line cannot fail a
bats test unless it is the last line of one.

Three of the six tests fail on this commit. xcatdsklspost reads CLEANUPXCATPOST
and never reads CLEANUPDISKFULLXCATPOST.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 501b1ba44d)
2026-09-24 13:22:06 +00:00
Daniel Hilst d6c2a0f5dc refactor(xcatdsklspost): put the /xcatpost cleanup in one routine
The decision to remove the postscripts from /xcatpost sits inline in the tail of
xcatdsklspost, where nothing can drive it without a management node and a real
download. A test of that decision has to grep the source of the script instead.

Move the decision into append_xcatpost_cleanup, above the
XCATDSKLSPOST_SOURCE_ONLY guard, so a test can source the script and call the
routine against a scratch directory. The routine takes the mypostscript path and
the xcatpost directory, and emits the same text as before for every value of
site.cleanupxcatpost.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 7c884cfe2f)
2026-09-24 13:22:06 +00:00
xcat2-backport-automation[bot] b3752a2fce Merge pull request #7875 from xcat2/backport-7843-to-2.19
[Backport 2.19] fix(xcat-core): grub2 cannot load the Ubuntu 26.04 ppc64el netboot initrd
2026-09-24 05:06:29 +00:00
Daniel Hilst 0336e02e6b fix(xcat-core): the initrd firmware step reads the root image only
The step that fills lib/firmware in the Ubuntu netboot initrd asked modinfo
about $rootimg_dir/$module and looked a firmware name up under lib/firmware.
The copy step beside it takes a module from $customdir or $pathtofiles first,
and the kernel looks a firmware name up under updates/<kernel>, updates/,
<kernel>/ and lib/firmware. So a custom driver reached the initrd with no
firmware, even when the root image carried it, and a firmware override was left
out of the initrd altogether.

initrd_firmware_files now takes the module directories the copy step searches
and the kernel release. It resolves each module in that order before asking
modinfo, and keeps every firmware file that exists in the four directories the
kernel searches, so the override still wins on the node.

ubuntu_genimage_initrd_firmware.t covers both: its two new cases are red on the
commit before this one.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 5554b79c2d)
2026-09-24 04:40:35 +00:00
Daniel Hilst 1d6493546c test(xcat-core): the initrd firmware step ignores custom drivers and firmware overrides
ubuntu_genimage_initrd_firmware.t drove the firmware step over a root image that
holds every module and every firmware file. It covered neither of the two places
genimage reads from beside the root image.

The test now puts a driver in the custom directory, with its firmware in the
root image, and a firmware override under lib/firmware/updates/<kernel>. Both
are red: the step asks modinfo about the module under the root image, where a
custom driver is not, and it looks for a firmware name under lib/firmware only,
where an override is not.

The five assertions that were there stay green.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 2523a06b16)
2026-09-24 04:40:35 +00:00
Daniel Hilst 9fc610ee94 fix(xcat-core): ubuntu_genimage_initrd_firmware.t passes when the file it reads is missing
ubuntu_genimage_initrd_firmware.t called plan skip_all when xCAT-server/share/xcat/netboot/ubuntu/genimage was absent, so a checkout that lost
the file reported 0 tests and exit 0. A test that cannot fail measures nothing.

Die instead, which is what makentp_ntp_deps.t already does for setupntp.

With xCAT-server/share/xcat/netboot/ubuntu/genimage moved aside the file now exits 2 and prints "genimage not found at <path>";
before this change it exited 0 and printed "1..0 # SKIP genimage not found at <path>". With the file
present the test passes either way.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 3c104421a2)
2026-09-24 04:40:35 +00:00
Daniel Hilst 6d37c76835 fix(xcat-core): grub2 cannot load the Ubuntu 26.04 ppc64el netboot initrd
The ubuntu-26.04-ppc64el diskless node never starts its kernel. SLOF reports
W3411 and E3406 and falls through to disk. The node fetches the kernel and the
initrd in under a minute and fails six minutes later, with no network activity in
between: grub2 has the payload and cannot start it.

genimage copies the whole lib/firmware tree of the root image into the initrd.
That tree is 666 MB on Ubuntu 26.04, which takes the initrd to 719 MB. A 687 MB
initrd boots the same kernel on the same node; a 719 MB one does not.

The firmware copy now takes only the firmware that the drivers in the initrd ask
for, which modinfo reports for each module. The root image keeps its whole tree,
so the node that boots is unchanged.

ubuntu_genimage_initrd_firmware.t drives the firmware step over a root image whose
firmware tree holds files no driver asks for. It fails on the previous commit.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 3fcc781fdd)
2026-09-24 04:40:35 +00:00
Daniel Hilst 3063ea24b7 test(xcat-core): the Ubuntu netboot initrd carries the whole firmware tree
The Ubuntu genimage copies every file under the root image lib/firmware into the
netboot initrd. On Ubuntu 26.04 that tree is 666 MB, and grub2 on a pseries node
cannot load the initrd it produces.

The test runs the firmware step of genimage over a root image whose firmware tree
holds files no driver in the initrd asks for, and reads the initrd that comes out.
It fails on the present code, which copies the tree whole.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 9c2068e26c)
2026-09-24 04:40:35 +00:00
xcat2-backport-automation[bot] eb08839b36 Merge pull request #7874 from xcat2/backport-7866-to-2.19
[Backport 2.19] fix(xcat-core): repository indexing fails on every target on a shared build tree
2026-09-24 03:55:31 +00:00
xcat2-backport-automation[bot] c912fc8023 Merge pull request #7873 from xcat2/backport-7862-to-2.19
[Backport 2.19] grant CREATE for xcatadm on pgsql15+
2026-09-24 03:46:30 +00:00
Daniel Hilst 1018efe39f fix(xcat-core): repository indexing fails on every target on a shared build tree
createrepo_dir passed --database, which writes *.sqlite.bz2. Building those
needs SQLite, and SQLite needs POSIX locks. A build tree can live on an NFS
re-export, where the kernel refuses locks outright: every attempt answers
errno 524.

So every target died with "Cannot open .repodata/primary.sqlite: Can not create
db_info table: disk I/O error", and the build staged nothing.

Measured on such a share, with a local control: a bare sqlite3 connect fails
there and succeeds on local disk; createrepo_c fails with --database and
succeeds without it, emitting primary/filelists/other as *.xml.zst.

Nothing this project ships reads the sqlite metadata. dnf on el8+ and zypper
both read the XML.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 0e6196524f)
2026-09-24 03:29:15 +00:00
Gary Skouson 6351292506 grant CREATE for xcatadm on pgsql15+
(cherry picked from commit 199de7f4f8)
2026-09-24 03:21:07 +00:00
xcat2-backport-automation[bot] 6bfdc037e2 Merge pull request #7871 from xcat2/backport-7870-to-2.19
[Backport 2.19] ci(genesis): run the OpenEmbedded check only when its inputs change
2026-09-23 19:37:35 +00:00
Vinícius Ferrão 404d1af1fb ci(genesis): run the OpenEmbedded check only when its inputs change
The OpenEmbedded metadata job ran on every pull request and took about
20 minutes. It reads only xCAT-genesis-builder/oe and
xCAT-genesis-scripts, and it pins its upstream sources to fixed commits.
A pull request that changes neither directory gets the same result each
time.

The job moves unchanged to its own workflow, which runs only when those
paths or the workflow file change. xcat_pr_test stays in xcat_test.yml
and runs on every pull request, because a required check that does not
run blocks the merge.

(cherry picked from commit 771da0e09e)
2026-09-23 19:10:02 +00:00