2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-21 23:28:19 +00:00
Commit Graph

10957 Commits

Author SHA1 Message Date
Vinícius Ferrão 937f6895f0 refactor(http): share port suffix formatting across boot callers 2026-10-14 13:29:22 -03:00
Vinícius Ferrão 6713d01af3 refactor(boot): share Genesis artifact selection 2026-10-14 13:29:22 -03:00
Daniel Hilst ba4824ef62 Merge pull request #7940 from VersatusHPC/fix/imgexport-destination
fix(imgport): write the imgexport bundle to its destination
2026-10-14 12:05:47 -03:00
Daniel Hilst bdd2a51efc Merge pull request #7945 from VersatusHPC/fix/imgimport-litefile-lookup
fix(imgport): quote the image column of the litefile lookup
2026-10-14 12:04:38 -03:00
Daniel Hilst c8a20a1ea2 Merge pull request #7950 from VersatusHPC/fix/kit-rhel-release
fix(kit): compare the RHEL release as a number
2026-10-14 11:53:59 -03:00
Daniel Hilst 675c9f3dfd Merge pull request #7946 from VersatusHPC/fix/kit-lock
fix(kit): refuse a kit command while another process holds the kit lock
2026-10-14 11:51:23 -03:00
Daniel Hilst 5c0944854f Merge pull request #7944 from VersatusHPC/fix/imgimport-extra-destination
fix(imgport): copy an extra file into its destination directory
2026-10-14 11:49:02 -03:00
Daniel Hilst b1fd47ae17 Merge pull request #7938 from VersatusHPC/fix/packimage-image-dir-glob
fix(packimage): refuse an image directory that the shell would split
2026-10-14 11:46:58 -03:00
Daniel Hilst 74ec6acdde Merge pull request #7900 from VersatusHPC/fix/x86-unstable-cases
fix(xcat-core): x86_64 CLI cases report failures the product does not have
2026-10-14 11:04:10 -03:00
Vinícius Ferrão bb94a545ff fix(kit): compare the RHEL release as a number
The kit commands refuse RHEL 8 and later, but compared the release as a
string. "10.1" sorts before "8", so the kit commands ran on RHEL 10.
They now compare the major release as a number.
2026-10-14 01:21:01 -03:00
Vinícius Ferrão 085ee7991d fix(imgport): copy an extra file into its destination directory
imgexport records an extra file with its destination directory. When
that directory did not exist, imgimport copied the file to the path of
the directory, so the file took the name of the directory. When a file
was at that path, imgimport replaced it.

imgimport now creates the destination directory and its missing
parents, as it does for an extra directory. A file at that path fails
the import and stays as it was. The copy runs without a shell, so a
file name with glob characters cannot match another file. A failed
backup of the previous file now fails the import.
2026-10-14 00:46:24 -03:00
Vinícius Ferrão bb885f2767 fix(kit): refuse a kit command while another process holds the kit lock
kit.pm tested the bareword locked instead of $locked. The test was
always false, so a kit command never took the kit lock, and it ran also
while another process held the lock.

A kit command now takes the lock in one step, and fails while another
process holds it. The is_locked probe is gone, because its release
removed the lock file that another kit command could then hold. A kit
command that another kit command runs goes on under the lock of that
command.
2026-10-13 23:34:38 -03:00
Vinícius Ferrão 9bfdadeaac fix(imgport): quote the image column of the litefile lookup
imgimport looked up the litefile entries for all images with "image" =
'ALL'. MySQL takes a double-quoted name for a string, so the lookup
found nothing, and imgimport added entries that an ALL entry already
covered. The lookup now quotes the column the way the database needs.
2026-10-13 23:22:01 -03:00
Vinícius Ferrão 0c6bd1ba1f fix(imgport): write the imgexport bundle to its destination
A local imgexport wrote the bundle to the current working directory and
kept only the file name of the destination, so a destination such as
/backup/images/compute.tgz went to ./compute.tgz. A destination in a
missing directory failed only after the image was copied.

imgexport now writes the bundle to the destination, and takes a
relative path from the current working directory. It checks the
directory before it copies the image. tar and scp take the path as an
argument without a shell, so a path with a space works.
2026-10-13 11:40:16 -03:00
Vinícius Ferrão 1a71d9d33c fix(packimage): refuse an image directory that the shell would split
packimage passes the image directory to shell commands without quotes,
such as the rm -rf of the xcatpost directory. It finds its abandoned
stages with glob. For an image directory such as
"/install/custom images/node", the shell and glob split the path at the
space, so packimage removed /install/custom with the images in it.

packimage now refuses an image directory whose path has a space or a
shell character, before it runs any command.
2026-10-13 11:38:51 -03:00
Daniel Hilst abf0f2228f Merge pull request #7935 from VersatusHPC/refactor/r26-package-lifecycle
refactor(packaging): share package lifecycle helpers
2026-10-13 10:00:14 -03:00
Vinícius Ferrão 49ffae9862 fix(packimage): replace the root image archive only after a complete pack
packimage deleted every rootimg.* file before it packed, and wrote the new
cpio or tar archive under its final name with mode 0600. Until the pack
finished, a node that booted got HTTP 403 for its image. When the pack
failed, the image was gone or left truncated, and no node could boot until
a later pack succeeded.

Build every archive in a temporary directory inside the image directory,
and rename the archive over the final name only after the pack succeeds,
as the openEuler path already did with a temporary file. With --tracker,
ctorrent builds the metainfo in the same directory, from the new archive
under its final name. The previous metainfo is removed before the archive
is renamed, and the new metainfo is renamed after it, so no failure
leaves a metainfo that describes another archive. The other rootimg.*
files are removed after the rename. The next pack on the same host
removes a temporary directory that an interrupted pack left. Image locks
are per host, so temporary directories of other hosts that share the
directory stay.

A pack now also fails when find cannot list the image or cpio cannot read
a file, as on the openEuler path. Before, only the compressor status
counted, and such a pack published an incomplete archive.

Every failure after packimage switches a StateLite tree to stateless files
now switches it back. That includes a failure to create the temporary
directory or the squashfs staging directory, which File::Temp reports
with die. packimage records each file that it moves and checks each move. When
a file cannot be moved back, the original stays in .statebackup,
packimage reports it, and the next pack refuses to run until the files
are restored. The new archive replaces the previous one only after the
StateLite files are back. Before, a failed pack left the tree switched,
and a retry overwrote the saved StateLite files.

The image lock is per host, and service nodes mount a shared image
directory without NFS locks. So a pack also holds the directory
.packimage-publish while it replaces the archive and removes the other
formats. mkdir is atomic for every host, also on NFS without locks. When
the lock is older than 60 seconds, or stays held for 60 seconds, the pack
fails, names the holder, and keeps the previous archive. packimage does
not take the lock over, because its holder can still be running.

A ctorrent failure now fails the pack, and the previous archive and
metainfo stay. Before, a failed ctorrent left a partial metainfo, and
nodeset pointed nodes at it.
2026-10-12 12:15:51 -03:00
Daniel Hilst aa05e7026b Merge pull request #7933 from VersatusHPC/refactor/r26-capture-lifecycle
refactor(dhcp): share the packet capture lifecycle
2026-10-12 10:54:00 -03:00
Daniel Hilst 1210e3c831 Merge pull request #7929 from VersatusHPC/refactor/r26-postinstall-bootstrap
refactor(postscripts): share the early postinit disable policy
2026-10-12 10:34:52 -03:00
Daniel Hilst ae9fd7912a Merge pull request #7932 from VersatusHPC/refactor/r26-string-trim
refactor(xcat): reuse whitespace trimming in blade and credential paths
2026-10-12 10:23:11 -03:00
Vinícius Ferrão cd90878516 refactor(init): share target detection and pending-state cleanup
Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-10-11 11:46:10 -03:00
Vinícius Ferrão cce001abb8 refactor(dhcp): share the packet capture lifecycle
Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-10-11 01:29:22 -03:00
Vinícius Ferrão 4879eef80b refactor(xcat): reuse whitespace trimming in blade and credential paths 2026-10-10 21:13:41 -03:00
Vinícius Ferrão 729b1b9aaa refactor(dhcp): reuse the hardware-address delete formatter 2026-10-10 17:41:20 -03:00
Vinícius Ferrão a987cfbd10 refactor(postscripts): share the early postinit disable policy
Embed one helper in the legacy and systemd postboot runners. Keep each
caller policy and disable the service before running postscripts.
2026-10-10 02:25:59 -03:00
Daniel Hilst 2840a965a6 Merge pull request #7903 from middelkoopt/tm-aarch64-mn
aarch64: management-node support (EL10 netboot pkglist + spec Requires)
2026-10-08 15:34:50 -03:00
Daniel Hilst 39037f7f2e style(xcat-core): the new case comments explain more than the code needs
The comments added with these fixes carried the bug history, the failing case
names and the reproduction detail. A reader of the code cannot act on any of
it, and the commit message already holds it.

Each comment is reduced to the one fact the code does not show: the platform
difference, the invariant, or the reason the simpler form is wrong.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-07 13:45:45 -03:00
Daniel Hilst ccac7e8c46 fix(xcat-core): write a Kea subnet for a relayed network
makedhcp <node> answers "Unable to find a Kea subnet for <node> (<ip>), skipping DHCP
reservation" for a node on a network whose mgtifname is "!remote!<nic>". The node gets no
reservation and never boots. The same cluster works with the ISC backend.

kea_build_dhcp4_intent skips a relayed network unless %activenics carries a "!remote!" key.
Nothing sets that key: %activenics comes from site.dhcpinterfaces or from the local routing
table, and a relay agent answers the network, so no local NIC carries it. The subnet4 is
absent and subnet_id_for_ip finds nothing for the node. The ISC path has no such condition.
Its @nrn loop writes the shared-network and the subnet from the networks table alone.

Require nothing for a relayed network, as ISC does. kea_subnet4_intent already leaves the
interface out of a relayed subnet, so Kea answers it through the relay.

The case that covers this is makedhcp_remote_network.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
(cherry picked from commit 62af5506dad06c7017c0d57a69d7ccc47a471dd5)
2026-10-07 13:45:18 -03:00
Daniel Hilst 5952dc04a2 Merge pull request #7594 from VersatusHPC/feat/fips-support
feat(fips): support installation on FIPS-enabled systems
2026-10-07 10:34:18 -03:00
Timothy Middelkoop d1faba077c feat(genimage): opt-in package signature checks for EL images
Add the linuximage gpgcheck attribute. When it is set to 1 or yes,
genimage passes --gpgcheck to the shared RPM image builder, which
exports the builder's trusted RPM keys exactly as it does for openEuler
and writes gpgcheck=1 with that gpgkey for the pkgdir, kerneldir and
otherpkgdir repositories. Unset keeps the existing unverified
configuration, openEuler stays always verified, and builders without
the option reject the attribute instead of ignoring it.

Collect the otherpkgs repositories in imgutils so that an otherpkgdir
holding only URLs no longer adds a file:/// repository that fails to
download metadata on EL.

Signed-off-by: Timothy Middelkoop <tmiddelkoop@internet2.edu>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 11:24:33 -05:00
Timothy Middelkoop d95b190461 aarch64: management-node support (EL10 netboot pkglist + spec Requires)
xCAT builds and runs on aarch64, but two pieces were missing for an EL10
aarch64 management node:

- No compute.rhels10.aarch64.{pkglist,exlist,postinstall}, so genimage
  fell back to the generic EL8/9-shaped compute.pkglist (dhclient,
  busybox-anaconda), which does not resolve on EL10 aarch64. Add the rh
  files (same content as the other EL10 architectures) with alma/rocky
  aliases, following the x86_64/ppc64le layout.
- xCAT.spec had Requires blocks for x86, ppc and riscv64 but none for
  aarch64, so an aarch64 install pulled no ipmitool-xcat. Add the block,
  mirroring riscv64: ipmitool-xcat plus ipxe-xcat (an aarch64 management
  node can serve x86 nodes); the x86-only PXE stack stays excluded.

Tests: extend el10_netboot_dhcp_client.t to the aarch64 lists and add
aarch64_packaging.t for the spec block and the netboot file layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Timothy Middelkoop <tmiddelkoop@internet2.edu>
2026-10-06 10:51:37 -05:00
Vinícius Ferrão b633f669c4 fix(dhcp): check SHA support only when OMAPI requires it 2026-10-05 22:54:27 -03:00
Vinícius Ferrão 45d773d5cd fix(kea): propagate invalid FIPS key policy 2026-10-05 22:53:29 -03:00
Vinícius Ferrão d01cb679eb fix(dhcp): share SHA-256 key policy in FIPS mode 2026-10-05 22:52:34 -03:00
Vinícius Ferrão 750ed7e5a5 fix(ssh): skip optional DSA host keys in FIPS mode 2026-10-05 18:14:20 -03:00
Daniel Hilst 6bc7800bba fix(xcat-core): deny the REST aliases when mod_rewrite is not loaded
xcat-ws.conf sends /xcatws and /xcatwsv2 to https only when mod_rewrite is
loaded. Without that module the aliases run the REST CGI on any port.

An IfModule !mod_rewrite.c block now answers 403 for both aliases.
RedirectMatch comes from mod_alias, which the ScriptAlias lines of the
same file already require. Other paths, such as /install, are not changed.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-05 14:03:14 -03:00
Daniel Hilst 469e108ff4 Merge upstream master into fix/xcat-ws-conf-module-path
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-05 13:50:47 -03:00
Daniel Hilst 74d5184963 fix(xcat-core): xcat-ws.conf names a SUSE module path and never matches its package
`rpm -V xCAT-server` reports /etc/httpd/conf.d/xcat-ws.conf and
/etc/apache2/conf.d/xcat-ws.conf changed on every EL, openEuler and SUSE
management node, for the life of the install. %install shipped the Apache 2.2
fragment as the payload, and %post replaced it with the Apache 2.4 fragment
whenever httpd, apachectl or apache2ctl reported 2.4. Every supported
distribution runs Apache 2.4, so the file on disk never matched the package
digest. The drift is a permanent false positive for anyone who verifies an
installed xCAT before trusting it.

Both fragments also began with
`LoadModule rewrite_module /usr/lib64/apache2-prefork/mod_rewrite.so`. That
file exists only on SUSE under the prefork MPM. Apache tolerates it on EL and
openEuler because conf.modules.d loaded mod_rewrite first, and logs AH01574;
where the module is not loaded first, the missing file stops Apache from
starting.

xcat-ws.conf.apache22 and xcat-ws.conf.apache24 are replaced by one
xcat-ws.conf that serves both generations: the redirect sits behind
<IfModule mod_rewrite.c>, and the authorization directives behind
<IfModule mod_authz_core.c> and its negation. %install copies that one file to
both conf.d paths and %post no longer names them, so the payload is the final
file. %post runs a2enmod rewrite where a2enmod manages modules, which is how
SUSE gets the module the removed LoadModule used to pull in.

xCAT-test/unit/wsapi_apache_conf_portable.t fails 22 of its 30 assertions
without this change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-05 11:25:38 -03:00
Vinícius Ferrão 4eacca2c9d fix(dhcp): stop an omshell query at its deadline
_run_omshell stops omshell after 10 seconds, but it read the output a
line at a time. A line read waits for a newline, and omshell writes its
prompt without one. An omshell that stalled after a prompt kept makedhcp
waiting past the deadline. The check of an external ISC server does that
read while it holds the DHCP lock.

_run_omshell now reads the output in chunks.
2026-10-02 23:58:15 -03:00
Vinícius Ferrão 8cf2640ee7 fix(dhcp): load a new ISC configuration before OMAPI changes a host
makedhcp builds a new configuration when dhcpd.conf is missing or xCAT
did not write it. It replaced each host over OMAPI before dhcpd loaded
that configuration. A dhcpd that still ran an older one then rejected a
host that tests an iPXE feature option. OMAPI had already removed the
old host, so the node lost its reservation.

makedhcp now writes the new configuration and restarts dhcpd first. It
changes no host when that restart fails. The restart marker of an
upgraded configuration now also covers a new one, so the next run
restarts dhcpd first after a run that stopped before the restart.
2026-10-02 23:58:15 -03:00
Vinícius Ferrão bec8d403eb refactor(dhcp): restart the ISC dhcpd of Linux in one place
A later change also restarts dhcpd before the host updates, with the
same distribution steps.
2026-10-02 23:58:15 -03:00
Vinícius Ferrão c63db068f9 fix(dhcp): boot the SAN disk of an installed node on Kea
Kea gave a node in state boot or iscsiboot no classes of its own and
left a node that boots from SAN out of the local-boot class. Its clients
fell to the shared classes, which now skip a client with the iPXE
features of a script. A firmware iPXE without iSCSI then got no loader,
and an iPXE with iSCSI got the discovery script of the network.

Such a node now gets the loader of its method from its own classes on a
client without iSCSI, for BIOS and, with netboot=ipxe, for UEFI, as its
ISC host statements do. A client with iSCSI is in the local-boot class,
so no class names a boot file for it and it boots the root path. Kea
tests the iSCSI feature, which xNBA and iPXE both report, for a node of
any method.
2026-10-02 23:58:15 -03:00
Vinícius Ferrão 79461a7280 fix(dhcp): keep an ISC host whose omshell line is too long
omshell reads 1023 bytes of a line and parses the rest as a new command.
makedhcp removes the old host of a node before it creates it again, so a
longer "set statements" line, as an iSCSI node with long target and
initiator names can give, left the node without its reservation.

makedhcp now checks every command of a host before it sends any. For a
node whose command is too long, it reports the node and leaves its host
unchanged.
2026-10-02 23:58:14 -03:00
Vinícius Ferrão 0e192f58c8 refactor(dhcp): build the omshell commands of an ISC host in one place
addnode printed the omshell commands of a host one line at a time,
starting with the removal of the old host. _isc_omapi_host_commands now
returns them as one text, so that makedhcp can check them before it
sends any. The commands and their order do not change.
2026-10-02 23:58:14 -03:00
Vinícius Ferrão 32a688b30a build: require ipxe-xcat alongside xnba-undi
Unknown x86 clients and netboot=ipxe nodes boot the upstream iPXE
loader of the ipxe-xcat package, which the xCAT packages did not
install.

The specs require ipxe-xcat where they require xnba-undi: on x86 and
ppc for xCAT, and on x86 for xCATsn. xCAT on riscv64 and xCATsn on ppc
and riscv64 require ipxe-xcat alone, because a POWER or riscv64 server
can serve x86 nodes. The xcat and xcatsn debs depend on ipxe-xcat on
every architecture for the same reason. go-xcat installs and removes
ipxe-xcat with the other packages.

xnba-undi stays a dependency, because netboot=xnba nodes still boot
xNBA.
2026-10-02 23:58:14 -03:00
Vinícius Ferrão 5461b767ca refactor(go-xcat): define the riscv64 filter before a sourced run returns
A sourced go-xcat returns before the main program, which defined
riscv64_install_list, so a test that sources the script could not call
the filter. The function is now defined above the main program. A run of
the script does the same as before.
2026-10-02 23:58:13 -03:00
Vinícius Ferrão 0f87fd2a00 fix(destiny): test the SAN loader of the netboot method of each node
setdestiny accepted an x86 iscsiboot node without iSCSI boot data only
when undionly.kpxe was in the TFTP root. The check read
-f ("$tftpdir/undionly.kpxe" or -f "$tftpdir/xcat/xnba.kpxe"): the or
was inside the -f argument, so xnba.kpxe never counted.

Accept the node when undionly.kpxe is there, or the BIOS file of the
loader of its netboot method: the upstream loader for netboot=ipxe, and
xNBA for any other method.
2026-10-02 23:58:12 -03:00
Vinícius Ferrão 6052edad42 feat(dhcp): warn when the upstream loader is not ready
makedhcp -n and -a now warn when a server that serves x86 discovery
lacks an upstream loader file in its local TFTP directory, the
snponly.efi that the UEFI shim loads included, or has no network boot
script under xcat/ipxe/nets, which mknb writes. A server
serves x86 discovery when it has network boot scripts under xcat/ipxe
or xcat/xnba. A node can load from another TFTP server, so the check
warns and does not stop.
2026-10-02 23:58:12 -03:00
Vinícius Ferrão 5269d7bf1c feat(netboot): define new x86 nodes with netboot=ipxe
netboot=xnba is deprecated, but profile-based node definitions, the x86
node templates of mkdef --template, the e1350 noderes table and the
SoftLayer importer still gave new x86 nodes xnba. They now give
netboot=ipxe, as node discovery does. Existing nodes keep their method,
and a profile change keeps netboot=xnba on a node that has it: moving a
node to the upstream loader is the choice of the site.
2026-10-02 23:58:12 -03:00
Vinícius Ferrão 48d774dfee feat(nodediscover): set netboot=ipxe on discovered x86 nodes
A discovered x86 node without an x86 method got netboot=xnba, which
names the xNBA loader that xCAT retires. It now gets netboot=ipxe, the
method of the upstream iPXE loader that discovery itself uses. A node
that already has pxe, ipxe or xnba keeps it.
2026-10-02 23:58:12 -03:00