2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-22 07:38:08 +00:00
Commit Graph

7180 Commits

Author SHA1 Message Date
Daniel Hilst 4a1a3a7eae Merge pull request #7830 from VersatusHPC/test/client-server-testing
test(xcat-core): Add client/server tests to xcat criticial points
2026-10-01 10:18:31 -03:00
Daniel Hilst 7950283276 Merge pull request #7891 from VersatusHPC/fix/kea-makedhcp-before-makedns
fix(dhcp): makedhcp -n fails on a new Kea management node before makedns -n
2026-10-01 09:05:12 -03:00
Daniel Hilst 988b1654e1 Merge master into test/client-server-testing
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-01 08:22:20 -03:00
Daniel Hilst 86d33741d7 Merge pull request #7889 from VersatusHPC/fix/service-node-ub
fix(xcat-server): an Ubuntu service node never installs, and never serves its compute node
2026-09-30 20:34:06 -03:00
Daniel Hilst 056a57f087 Merge branch 'master' into feature/openeuler-lts 2026-09-30 17:50:25 -03:00
Daniel Hilst c2b8772fd4 fix(xcat-core): makedhcp -a after makedns -n leaves Kea DDNS off
On a new Kea management node, makedhcp -n defers DDNS until makedns -n
writes the key. makedhcp -a then applied the D2 settings to the fresh
intents, but saved the loaded configurations, which had no dhcp-ddns.
It also wrote no kea-dhcp-ddns.conf, so DNS updates stayed off.

When DDNS is on and the loaded DHCPv4 configuration has no dhcp-ddns,
makedhcp -a now copies the D2 settings into the loaded DHCPv4 and DHCPv6
configurations, writes the D2 configuration and, when enabled, the
Control Agent configuration. It then enables and restarts the Kea
services.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-30 12:54:38 -03:00
Daniel Hilst fae3e69d40 Merge pull request #7890 from VersatusHPC/fix/nodepurge-leaves-autoinst-directory
fix(xcat-core): nodepurge leaves the autoinstall directory of an Ubuntu node
2026-09-30 06:24:57 -03:00
Daniel Hilst 5e69d912ec refactor(xcat-core): report the Kea DDNS deferral through the warning key
kea_build_ddns_intent returned the deferral under a deferred key. No other
xCAT code uses that key: dhcp.pm reports through error, warning, node and
data, and makedhcp already passed this message to the callback as a warning.

The intent hash now carries the message under warning, so one name describes
it from the hash to the callback. Behaviour does not change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-29 22:28:58 -03:00
Daniel Hilst 22b43ff7b3 docs(xcat-core): cut the rationale from the Kea DDNS comment
The comment stated the xcatconfig default and then repeated the reason for the
change, which the commit message already carries. Keep the condition only.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-29 21:37:36 -03:00
Daniel Hilst 0994650dac fix(xcat-core): makedhcp -n fails on a new Kea management node
makedhcp -n fails on a new management node that uses the Kea backend:

    Error: Unable to find DDNS key material for Kea D2. Run makedns with
    dnshandler=ddns first.

xcatconfig writes site.dnshandler=ddns on every new installation, so
kea_ddns_enabled reports DDNS on, and kea_build_ddns_intent then requires
/etc/xcat/ddns.key. Only makedns -n writes that file. The ISC backend reads no
key, so an ISC management node runs makedhcp -n without one. The Kea backend
plan states that basic DHCP and PXE support must not depend on DDNS.

kea_build_ddns_intent now reports a deferral instead of an error when it finds
no key material. kea_apply_ddns_intent attaches the D2 connection only when a
key exists, and returns the deferral for makedhcp to print as a warning. A
management node with key material gets the same configuration as before.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-29 20:25:04 -03:00
Daniel Hilst 74c82463de docs(xcat-server): the Ubuntu service node comments retold the incident
The comments added with the Ubuntu fixes carried the bug report and its
consequences: what a compute node stops at, what named answers to every query
once its working directory is unwritable, and that a failed export does not fail
the service node. The comment rules keep the invariant in the source and put the
symptom and the chain in the commit.

Each is cut to the fact the code cannot show: that the resolv.conf a
systemd-resolved host publishes holds a stub pointing back at this named, that
named must be able to write the directory it drops privileges into, that apt
refuses an unsigned repository, and that re-exporting a mount needs an fsid.

service.subiquity.tmpl keeps its header, which is identical to the sibling
compute template and should stay that way.

No executable line changes.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-29 19:40:25 -03:00
Daniel Hilst 1fa9d1f6fc test(xcat-core): nodepurge leaves the autoinstall directory of an Ubuntu node
nodepurge removes the autoinstall configuration of each node it deletes. The
cleanup loop was inline in the nodepurge sub of profilednodes.pm, which no test
can load, so the loop moves to xCAT::ProfiledNodeUtils->remove_node_config_files
with its behaviour unchanged.

nodepurge_autoinst_cleanup.t drives that routine against a scratch directory. It
fails here: the Subiquity node keeps its directory, and the preseed file and the
.pre and .post scripts are removed.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-29 18:19:19 -03:00
Daniel Hilst 14f0e13ec4 fix(xcat-server): a Debian service node's named serves the wrong configuration
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-29 17:18:05 -03:00
Daniel Hilst 4997fa14a1 fix(xcat-server): a service node that mounts /install serves no NFS
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-29 17:18:05 -03:00
Vinícius Ferrão 63cf366b96 Merge master into feature/openeuler-lts 2026-09-29 00:01:05 -03:00
Daniel Hilst 9aca68e64b fix(xcat-core): Kea offers xnba.efi to a node deferred to proxyDHCP
A Windows UEFI install deferred to proxyDHCP gets boot-file-name "" in its
Kea reservation. Kea treats the empty string as not specified, so the
subnet classes still match on architecture, and xcat-uefi-x64 offers
xcat/xnba.efi. The firmware then boots xNBA instead of asking the
proxyDHCP daemon on port 4011.

kea_node_client_classes_for_nodes now also puts the MAC of a proxyDHCP
node in xcat-localboot, which every class that names a boot file already
excludes. The per-node class that sets option 60 to PXEClient names no
boot file and still matches.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-28 14:48:14 -03:00
Daniel Hilst e747f015bb Merge master into test/client-server-testing
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-28 14:30:14 -03:00
Daniel Hilst 417d22e9c1 Merge pull request #7876 from VersatusHPC/fix/mknb-bootif-hexhyp
fix(mknb): pass the boot MAC to BIOS Genesis on stock iPXE
2026-09-25 09:03:46 -03:00
Vinícius Ferrão 463eca19e5 Merge master into feature/openeuler-lts 2026-09-25 01:41:02 -03:00
Daniel Hilst eb595c698c Merge pull request #7834 from VersatusHPC/fix/ubuntu-subiquity-ppc64le-grub-ieee1275
fix(xcat-core): the Ubuntu ppc64le diskful install stops without grub-ieee1275
2026-09-24 10:57:04 -03:00
Vinícius Ferrão b4eb93be86 fix(mknb): pass the boot MAC to BIOS Genesis on stock iPXE
mknb wrote BOOTIF=01-${netX/machyp} into the BIOS Genesis script.
machyp is an xNBA setting, and stock iPXE expands it to an empty string.
Without the boot MAC, the legacy Genesis stops with "Unable to find boot
device" after at least 10 minutes. The OpenEmbedded Genesis fails at once
with BOOT_INTERFACE_NOT_FOUND.

Use ${netX/mac:hexhyp}, as the UEFI Genesis script and xnba.pm do. xNBA
expands both settings to the same value, so boot with xNBA is unchanged.
2026-09-24 02:33:01 -03:00
Vinícius Ferrão 16b6acf620 fix(openeuler): integrate current Genesis and installer changes
Merge current master into the openEuler support branch. Keep native
kernel, DHCP, locale and timezone requirements with the upstream payload
verifier and EL10 package paths. Preserve signed openEuler installation.

Update the native fixtures to check the merged payload contract.
2026-09-22 19:45:05 -03:00
Vinícius Ferrão 63e80a3734 fix(xnba): correct ownership checks in disjoint DHCP mode 2026-09-19 04:18:18 -03:00
Daniel Hilst 2f715ac371 Merge pull request #7818 from VersatusHPC/release/2.19-rc1
ci(xcat-core): Fixes to get CI running for all 2.19 targets
2026-09-17 18:18:48 -03:00
Daniel Hilst 2e6ca07172 Merge pull request #7841 from VersatusHPC/fix/ubuntu-power-diskful-installer-loop
fix(xcat-core): the Ubuntu POWER diskful install never leaves the installer
2026-09-17 12:38:17 -03:00
Daniel Hilst d694456244 Merge pull request #7855 from VersatusHPC/fix/ddns-tsig-algorithm-downgrade
fix(xcat-core): makedns leaves records behind because named cannot verify its own TSIG key
2026-09-17 11:39:44 -03:00
Daniel Hilst 6a41acf2db fix(xcat-core): the retried DNS update carries two TSIG records
makedns reports "error was FORMERR" for an update that named rejected with
NOTAUTH. The FORMERR is the answer to the retry, not to the first attempt.

send_ddns_update in ddns.pm signs the packet the caller built, and signs that
same packet again on each attempt. Net::DNS::Packet::sign_tsig appends the TSIG
to the additional section, so the second attempt sends two TSIG records and
named answers FORMERR. FORMERR is neither NOTAUTH nor SERVFAIL, so the routine
stops and reports it. The NOTAUTH and SERVFAIL retry can never be accepted, on
any algorithm.

Each attempt now signs a request of its own. A packet cannot be unsigned again,
so ddns_update_request copies the prerequisite and update records into a new
Net::DNS::Update instead, and the caller keeps the unsigned original.

ddns_update_retry.t fails before this change: the second attempt carries two
TSIG records, and an update that the retry answers with NOERROR still reports
failure.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-15 20:43:58 -03:00
Daniel Hilst 4eb9718548 fix(xcat-core): makedns rewrites its own TSIG key and then fails against it
makedns exits 1 on a management node that has Net::DNS below 1.36 and an
hmac-sha256 key, and reports "Failure encountered updating <zone> with entry
'', error was FORMERR".

update_namedconf in ddns.pm rewrites the named.conf key stanza to hmac-md5
whenever Net::DNS is below 1.36, and ddns_tsig_algorithm returns hmac-md5 for
the same reason. ddns_sign_update signs with site.dhcpomapialgorithm, which
xcatconfig sets to hmac-sha256 on EL9 and later. named matches a TSIG key by
name and by algorithm, so it answers NOTAUTH. The retry signs the same packet
a second time, and named answers FORMERR to the two signatures.

The version test protected the two-argument sign_tsig($name, $secret), which
produces an HMAC-MD5 signature only. ddns_sign_update signs every other
algorithm through a KEY RR, so the Net::DNS version no longer selects the
algorithm. This change deletes the rewrite and the version test, and signs with
the algorithm the key stanza declares. OmapiPolicy->algorithm_rr_type maps that
algorithm to its KEY RR number.

ddns_named_key_algorithm.t fails before this change: it reads the stanza as
hmac-md5 where the key was hmac-sha256.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-15 20:43:58 -03:00
Vinícius Ferrão c0e66721d7 feat(openeuler): provision installed and diskless images
Add native compute and service profiles, installer dispatch and partition
defaults. Use strict DNF image creation. Check stateless boot-file and
archive publication. Preserve native image customizations on reimport.
Restore missing image records during reimport.
2026-09-15 01:12:21 -03:00
Vinícius Ferrão ac8fe0275f feat(openeuler): render repositories from configured install root 2026-09-15 00:40:55 -03:00
Vinícius Ferrão 5857091e46 feat(openeuler): recognize native installation media 2026-09-15 00:17:04 -03:00
Vinícius Ferrão 6af317f7da feat(openeuler): resolve native provisioning profiles 2026-09-15 00:10:12 -03:00
Vinícius Ferrão 2652cb152f feat(openeuler): use native NetworkManager configuration
Reuse NetworkManager for persistent routes, bond setup and connection
properties on openEuler. Preserve ifcfg handling where the connection still
uses it. Propagate route failures to local callers.
2026-09-14 23:15:14 -03:00
Daniel Hilst 4ccac9abae test(xcat-core): a failed extraction stops the whole suite, and the DHCP comments repeat
dhcp_ddns_policy.t and dhcp_isc_expression_grouping.t called BAIL_OUT
when a routine was missing or the plugin could not be read. prove stops
every remaining file on a bail-out, so one of them hides the results of
every test that would have run after it. die is just as loud and costs
only its own file.

Three facts in this branch were each written out in four places. That
SIGHUP reports success before Kea reads the file appears in Kea.pm twice
and in dhcp.pm again; that an installed node netboots when no boot file
reaches it appears in BootPolicy.pm and three times in dhcp.pm; the
dhcpd grouping rule appears in BootPolicy.pm and in the test header. Each
now stands once, without the symptom narration and the defect history
around it.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-14 08:44:38 -03:00
Daniel Hilst db820cfcc0 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>
2026-09-14 08:29:39 -03:00
Daniel Hilst 5570a4c64a fix(xcat-core): the Ubuntu POWER diskful install never leaves the installer
reg_linux_diskfull_installation_flat fails on ubuntu-22-ppc64le-devel and
ubuntu-24-ppc64le-devel in build #121 of xcat-core-devel-ubuntu-cd. The
Subiquity installer starts, errors in its early-commands, tars
/var/log/installer to port 8080 and reboots, nine times in 75 minutes. No
system is ever installed, so the address answers from the live installer and
the case ends on
"root@xcat25-cn: Permission denied (publickey,password)".

mkinstall in xCAT-server/lib/xcat/plugins/debian.pm selected
pre.ubuntu.subiquity and then replaced it with pre.ubuntu.ppc64 for every
ppc64 node, whichever installer was in use. pre.ubuntu.ppc64 writes a partman
recipe, and the early-commands append it to /autoinstall.yaml, which Subiquity
cannot parse.

pre.ubuntu.subiquity offered a UEFI branch and a BIOS branch, so a ppc64el node
took the BIOS branch and was given a bios_grub partition. POWER firmware loads
the boot loader from a PReP partition.

install_prescript now returns the script from the installer and the
architecture together, and the ppc64 script is reached only on the
debian-installer path. pre.ubuntu.subiquity gains a PReP branch, taken when
uname reports a POWER machine, which flags an 8M first partition prep and makes
that partition the grub device.

debian_install_prescript.t and the PReP case of ubuntu_subiquity_storage.t fail
without these changes.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-14 07:27:58 -03:00
Daniel Hilst 5d0f6fc50d 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>
2026-09-12 14:26:09 -03:00
Daniel Hilst 18d5c78121 refactor(dhcp): the DDNS zone block is written twice and the copies disagree
addnet and addnet6 each build the zone and key statements that let dhcpd
update the cluster's DNS. The two copies drifted: addnet writes "primary" only
when a server is known, addnet6 writes it unconditionally and emits
"primary ; key xcat_key;" for a network whose nameservers are unset. Neither
copy can be driven from a test, because both sit in the middle of a routine
that needs the whole plugin's globals.

isc_ddns_zone_statements takes the decision and returns the lines. The callers
keep the side effect and the _omapi_settings lookup. addnet6 gains addnet's
guard, and a network with neither a ddnsdomain nor a domain now writes no zone
at all rather than "zone . {".

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-12 10:13:49 -03:00
Daniel Hilst a2b4b5a690 fix(dhcp): a client naming itself takes over a Kea node's name
kea_node_reservations in xCAT-server/lib/xcat/plugins/dhcp.pm writes the node
name only as the reservation's host-name option. Kea reads the lease name and
the DDNS name from the reservation's "hostname" field, so with that field
absent it uses the name the client put in option 12. A node that calls itself
"ubuntu" -- which the Ubuntu installer does -- gets the DNS record for the
node's address and is told "ubuntu" back.

The reservation carries the hostname field again. The host-name option stays,
so a server that sends it verbatim still sends the short name.

The field is qualified by Kea 2.4 before it reaches option 12, so a node on a
cluster with DDNS is told "node01.cluster" where ISC says "node01". S-35 in
netboot-methods.conf asserts the label rather than the whole option for that
reason, and dhcp_kea_plugin_intent.t asserts the field is present.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-12 09:29:57 -03:00
Daniel Hilst 24e22671b4 Merge branch 'master' of https://github.com/xcat2/xcat-core into release/2.19-rc1
master moved 149 commits ahead of the branch point and four files needed a
decision.

xCAT/debian/control and xCATsn/debian/control: master moved nmap and
ipmitool-xcat into Depends, raised the ipmitool version and added the s390x
OpenEmbedded Genesis recommendation. The branch made the genesis-scripts
dependency per architecture. Both are kept, so the ppc64el metapackage depends
on xcat-genesis-scripts-ppc64el and no longer on the amd64 package.

build-utils/lib/XCAT/BuildUtils.pm and xCAT-test/unit/build_utils.t: master
replaced @DEB_ARCHES plus the branch's %NO_RISCV64 exception list with
%ARCH_PACKAGES, which carries the architecture list per package.
deb_package_arches returns the same answer for every package, so master's form
is kept and %NO_RISCV64 is dropped.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-11 15:59:58 -03:00
Daniel Hilst 0c27708c0f fix(xcat-core): nodeset cannot boot an Ubuntu POWER install from live media
nodeset stops the diskful install on every ppc64le cell of
xcat-core-devel-ubuntu-cd (build #119, ubuntu-24-ppc64le-devel):

    xcat25-cn: The network boot initrd.gz is not found in
    /install/ubuntu24.04.4/ppc64el/install/netboot.

The Ubuntu ppc64el live-server ISO carries no netboot tree. The installer
kernel and initrd sit under casper. Two places in
xCAT-server/lib/xcat/plugins/debian.pm reject that media: %INSTALL_BOOT_FILES
describes no casper layout for POWER, and mkinstall applies a second,
POWER-only precondition on install/netboot/initrd.gz before it calls the
resolver.

The POWER table now carries casper/hwe-vmlinux + casper/hwe-initrd and
casper/vmlinux + casper/initrd, after the netboot entries so a netboot tree
still wins. install_media_is_bootable replaces the POWER-only precondition, so
one routine decides what media can boot.

debian_install_boot_files.t resolves the POWER casper layouts and drives
install_media_is_bootable. It fails without this change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-11 15:09:27 -03:00
Vinícius Ferrão ac50225541 feat(Template): render the osimage pkglist into the autoinstall package list
A Subiquity autoinstall installs what its user-data packages list names,
and the templates could only name a fixed set, so the osimage pkglist
reached an Ubuntu node through ospkgs after the first boot. The preseed
token has no autoinstall form: the package list is YAML, one item per
line.

A list line that carries #INCLUDE_DEFAULT_PKGLIST_AUTOINSTALL# is now
replaced by one item per pkglist package at the same indentation, with
includes followed and without repeating the items the template lists
above it. The line is replaced in the include pass of subvars, so a site
template that includes the stock one is served too. A plain name and a task are
installed this way, and a comment after them ends the record. A version
pin or a target release stays with ospkgs, because the installer runs
apt-get without --allow-downgrades and a pin can require one, and so does
a name with an architecture qualifier, because a foreign architecture is
enabled by a postscript that runs later. A record that begins with
a removal or a group is left out whole, as ospkgs removes or installs it
whole, and so are a removal written with a trailing hyphen, markers and
preseed directives. A list that carries a #ENV: setting or an unreadable
include is left to ospkgs whole. So is the list of an osimage with
environvar, which mkinstall now hands over, and such an image's pkgdir
mirrors stay out of the installer's sources as well: those variables
reach apt-get only through ospkgs, and a mirror may need them. An osimage
without a pkglist loses only the token line.

The installer's apt configuration turns recommended packages off, as
ospkgs installs the list without them; curtin writes that setting into
the target, where the template removes it with the installer's sources.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-11 11:38:15 -03:00
Vinícius Ferrão a7812caca8 feat(Postage): read a pkglist as whole records
get_pkglist_tex joins the records of a pkglist with commas for the preseed
and OSPKGS consumers, so a caller that needs the records themselves cannot
recover a record that contains a comma, such as a tasksel directive. The
new reader returns the records whole, comments dropped and includes
followed in place. It reads each line as get_pkglist_tex does and resolves
every include, nested ones too, against the directory of the listed
pkglist, as get_pkglist_tex does. The comma text is unchanged.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-11 11:38:15 -03:00
Vinícius Ferrão 539486b7c8 feat(Template): give the Subiquity installer the pkgdir mirrors
An osimage pkgdir can name mirrors after the install media, and ospkgs
installs from all of them, but the autoinstall apt configuration offered
the installer only the archive mirror and the otherpkgs repositories. A
package that only a pkgdir mirror carries could not be installed before
the first boot.

The mirrors now join the installer's apt sources, next to the otherpkgs
ones, in every form the configuration takes. An entry written as URL,
suite and components is an apt source line, as ospkgs writes it, and a
suite that is an exact path needs no component. A local directory that
is a flat repository is served by the management node and trusted, as an
otherpkgdir is. An entry that names an Ubuntu archive mirror the
installer already has a source for, the configured one or a default one,
carries that source's signing key, the archive keyring on the Deb822
releases and none before them, because apt rejects a second source for
the same suite whose signing key differs. For the same reason a
repository is offered once, whether pkgdir names it twice, as a directory
and as its URL, or the otherpkgdir names it too. Anything
else is no apt source for ospkgs either and is left out.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-11 11:38:15 -03:00
Daniel Hilst a47e63141d docs(dhcp,provtest): cut the comments back to what a reader needs
The branch's own comments had grown to explanations of the reasoning
behind each decision. Trim them to the fact and its consequence: why a
line exists, and what breaks without it. Long blocks come down to a
hundred words, most to twenty or fewer, and the file headers keep only
their usage tables and the invariant each suite rests on.

No code changes. Every unit test, scenario validation and syntax check
still passes.
2026-09-11 10:13:23 -03:00
Daniel Hilst 5a969c8eb7 fix(credentials): refuse a getcredentials request naming no credential
Which credential is wanted is named in <arg>. A request without one
reached a dereference of an undefined array ref, so xcatd died inside the
plugin and shipped the Perl error back to the client instead of ignoring
the request.

Check for the element before the callback is made, and log and drop the
request the same way a bad callback port is dropped. A client that sends
a malformed request now learns nothing about the server, which is the
point: this path hands out cluster certificates to anything whose address
resolves.
2026-09-11 09:00:35 -03:00
Daniel Hilst a64dfe149a fix(dhcp): stop handing an installed node a boot file on either backend
A node that has finished installing has chain.currstate "boot", and from
that point the server must stop naming it a boot file: a node given a
netboot script every time it powers on reinstalls itself forever, and does
so silently, because each individual boot looks like a successful one.

Neither backend did that. The wire suite found both.

ISC gated the whole boot-from-disk branch on $doiscsi, so the rule only
fired for a node with an iscsi table row. An ordinary installed node fell
through to the netboot branches below and its xNBA second stage was handed
its own install script. Both the xnba and the pxe branch had it; the pxe
one handed out pxelinux.0.

Kea reads "boot-file-name": "" as *unspecified*, not as "no boot file", so
the empty boot file on the node's reservation did not outrank the classes
every client shares. The always-evaluated xcat-bios class supplied
xcat/xnba.kpxe, the loader came back announcing user class xNBA, and the
per-network class then supplied the network's boot script -- so withholding
only the per-node script withheld nothing. The fix is the same mechanism the
DROP and NOIP classes already use: a xcat-localboot class holding the MACs,
and a "not member('xcat-localboot')" guard on every class that names a boot
file. Kea requires a class to be defined before it is referenced, so
xcat-localboot is written first.

iSCSI is the exception on both backends. Its root disk is on the network and
gPXE is what attaches it, so it still gets a loader: ISC keeps its $doiscsi
branch, and Kea leaves those MACs out of the class.

spec.md S-31 is rewritten to say what correct is -- no boot file at all, on
either request of an xNBA boot, whatever the netboot method -- rather than
the weaker "not its own script", which the second stage above shows is not
the same statement.

conf/localboot.conf asserts the stronger form and gains a netboot=pxe node,
since that branch is written separately and the xnba node passing says
nothing about it. dhcpfixture.sh defines it.

An assertion with != or not-in now holds against a target that is absent
from the reply: a reply naming no boot file has certainly not named the
node's install script. Every other operator still fails on absence, and
"absent" remains the way to assert absence itself.
2026-09-10 17:36:44 -03:00
Vinícius Ferrão e36cdec3e9 fix(Template): give the installer otherpkgs sources apt can read
The online autoinstall apt configuration offered every otherpkgdir entry
as a flat one-line source with trusted=yes. From 24.04 on curtin
converts a one-line source to Deb822 before it writes the file and keeps
only the type, URI, suite and components, so the unsigned repository
reached apt without the option and apt rejected it during the install.
An entry written as URL, suite and components, the form the otherpkgs
documentation gives for a mirror, was written whole as the URL, which
apt cannot parse either.

The sources are now Deb822 stanzas on those releases, which curtin
writes as they are, with Trusted: yes, and a mirror entry keeps its
suite and components as fields. The releases before 24.04 keep the
one-line form, with the same fields.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-10 17:34:01 -03:00
Daniel Hilst cb345bba06 fix(dhcp): let a Kea reservation name a node without qualifying it
S-35 asks both backends to tell a node its own name in option 12. The
previous attempt wrote the reservation's hostname with a trailing dot, on
the reading that a name already fully qualified is not qualified again.
That is true of Kea 3.0, which is what it was tested against, and false of
Kea 2.4, which is what Ubuntu 24.04 ships and what CI runs: it appends
ddns-qualifying-suffix regardless and the node was told
"node01.pok.stglabs.ibm.com" where ISC said "node01".

Confirmed against both versions with a reservation on a veth pair, DDNS
configured, asking for option 12:

  reservation hostname "probenode."          2.4.1 -> probenode.example.test
                                             3.0.3 -> probenode
  hostname "probenode." and option-data      2.4.1 -> probenode.example.test
  option-data host-name only                 2.4.1 -> probenode
                                             3.0.3 -> probenode

So a reservation's option-data cannot override the field either --
processHostnameOption adds option 12 before appendRequestedOptions runs,
and appendRequestedOptions only fills in what is not already there.
Leaving the hostname field out is the one form that answers with the
node's own name on both versions, and it is also the shape ISC has: an
option statement, separate from the ddns-hostname statement beside it.

kea_boot_for_node already emits the host-name option for every node, so
nothing needed to be added -- only the field removed.

Two consequences, both intended. Kea no longer has a per-reservation DDNS
name and will use whatever the client sends, which is what a cluster with
xCAT's own DNS already relies on; ddns-qualifying-suffix still qualifies
the dynamic clients that have no reservation. And `makedhcp -q` now reads
the name back out of the host-name option, because that is where it is.
2026-09-10 16:44:42 -03:00
Daniel Hilst 05185b13db fix(dhcp): make Kea and ISC agree on the wire where the spec says they must
The wire suite compared the two backends against xCAT-test/dhcptest/spec.md and
found four places where a node was told different things depending on which
daemon answered. Each is fixed at the side the spec calls correct.

Option 12 (S-35): Kea builds the host-name option out of a reservation's single
`hostname` field and runs it through ddns-qualifying-suffix on the way out, so a
node asking who it was got "node01.cluster.example.com" while ISC, which writes
option 12 and the DDNS name from separate statements, said "node01". A name that
already ends in a dot is fully qualified and is not qualified again, so the
reservation is now written "node01." -- the wire agrees with ISC, and the suffix
still qualifies the dynamic clients that have no reservation. A reservation's
option-data cannot be used for this: processHostnameOption adds option 12 before
appendRequestedOptions runs, and appendRequestedOptions only fills in options
that are not already present. Reservation lookups are made dot-insensitive so
`makedhcp -d` and `-q` keep matching a node by its bare name.

Option 43 / ISAN (S-20): Kea appends an encapsulated space to a reply only when
the option that carries it is configured too, and option 43 is `type: empty`
with `encapsulate: isan`. Naming only the isan-space sub-options left them with
nothing to travel in and the initiator was offered an address with no target, so
the empty container is now named alongside them. ISC needs no equivalent --
declaring `option isan.iqn` builds option 43 for it.

Boot file fallback (S-12): dropping an architecture branch from the ISC if/else
chain let that client fall through to the final `substring(filename,0,1) = null`
catch-all and be handed /yaboot, which is the loader substitution the spec
forbids. Suppressed architectures now get an explicit empty branch. Kea cannot
have this bug: its classes are independent and xcat-fallback excludes every
recognised arch.

Reload (S-40): `systemctl reload kea-dhcp4` returns 0 once the signal is
delivered, and Kea can then reject the config and keep serving the old one while
systemctl still reads active -- a node added by discovery was never adopted.
dhcp4 and dhcp6 intents therefore always carry a control-socket, and a reload
goes over it so the daemon reports whether it took, falling back to
reset-failed + restart when it cannot confirm.

The fixture now proves a daemon actually holds port 67 before it believes the
backend is serving, which is what turned the reload failure from a flake into a
reproducible case.

Verified on the wire against both backends on EL10 with dhcpd 4.4.3 and
kea 3.0.3: all ten cases rc=0 on each. Unit suite 848/848.
2026-09-10 15:57:33 -03:00